diff --git a/Cargo.lock b/Cargo.lock index 279f4eaae0..04bdf7e9c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1266,16 +1266,14 @@ dependencies = [ "bincode", "hex", "indexmap", + "leo-asg", "leo-ast", - "leo-core", "leo-gadgets", "leo-grammar", "leo-imports", "leo-input", "leo-package", "leo-state", - "leo-symbol-table", - "leo-type-inference", "num-bigint", "pest", "rand", @@ -1292,22 +1290,7 @@ dependencies = [ "snarkvm-utilities", "thiserror", "tracing", -] - -[[package]] -name = "leo-core" -version = "1.0.8" -dependencies = [ - "leo-ast", - "leo-gadgets", - "rand", - "rand_xorshift", - "snarkvm-curves", - "snarkvm-errors", - "snarkvm-gadgets", - "snarkvm-models", - "snarkvm-utilities", - "thiserror", + "uuid", ] [[package]] @@ -1344,6 +1327,7 @@ name = "leo-imports" version = "1.0.8" dependencies = [ "indexmap", + "leo-asg", "leo-ast", "leo-grammar", "thiserror", @@ -1438,33 +1422,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "leo-symbol-table" -version = "1.0.8" -dependencies = [ - "indexmap", - "leo-ast", - "leo-core", - "leo-grammar", - "leo-imports", - "serde", - "thiserror", -] - -[[package]] -name = "leo-type-inference" -version = "1.0.8" -dependencies = [ - "indexmap", - "leo-ast", - "leo-grammar", - "leo-imports", - "leo-symbol-table", - "serde", - "serde_json", - "thiserror", -] - [[package]] name = "libc" version = "0.2.81" diff --git a/Cargo.toml b/Cargo.toml index 129dbe8739..2bba76deb9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,6 @@ path = "leo/main.rs" members = [ "ast", "compiler", - "core", "gadgets", "grammar", "imports", @@ -37,8 +36,6 @@ members = [ "package", "state", "asg", - "symbol-table", - "type-inference" ] [dependencies.leo-ast] diff --git a/ast/src/common/identifier.rs b/ast/src/common/identifier.rs index 1b130a6c55..40df67aabf 100644 --- a/ast/src/common/identifier.rs +++ b/ast/src/common/identifier.rs @@ -88,10 +88,6 @@ impl Identifier { pub fn is_self(&self) -> bool { self.is_self_type() || self.name == "self" } - - pub fn is_core(&self) -> bool { - self.name.starts_with('#') - } } impl<'ast> From> for Identifier { diff --git a/compiler/Cargo.toml b/compiler/Cargo.toml index d682aa3343..39157ac485 100644 --- a/compiler/Cargo.toml +++ b/compiler/Cargo.toml @@ -21,10 +21,6 @@ edition = "2018" path = "../ast" version = "1.0.8" -[dependencies.leo-core] -path = "../core" -version = "1.0.8" - [dependencies.leo-gadgets] path = "../gadgets" version = "1.0.8" @@ -49,12 +45,8 @@ version = "1.0.8" path = "../state" version = "1.0.8" -[dependencies.leo-symbol-table] -path = "../symbol-table" -version = "1.0.8" - -[dependencies.leo-type-inference] -path = "../type-inference" +[dependencies.leo-asg] +path = "../asg" version = "1.0.8" [dependencies.snarkvm-curves] @@ -116,6 +108,10 @@ version = "1.0" [dependencies.tracing] version = "0.1" +[dependencies.uuid] +version = "0.8" +features = ["v4", "serde"] + [dev-dependencies.num-bigint] version = "0.3" diff --git a/compiler/src/compiler.rs b/compiler/src/compiler.rs index 7fc9fc6846..f272113f2e 100644 --- a/compiler/src/compiler.rs +++ b/compiler/src/compiler.rs @@ -25,13 +25,11 @@ 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 leo_asg::Program as AsgProgram; use snarkvm_dpc::{base_dpc::instantiated::Components, SystemParameters}; use snarkvm_errors::gadgets::SynthesisError; use snarkvm_models::{ @@ -54,7 +52,7 @@ pub struct Compiler> { output_directory: PathBuf, program: Program, program_input: Input, - imported_programs: ImportParser, + asg: Option, _engine: PhantomData, _group: PhantomData, } @@ -70,7 +68,7 @@ impl> Compiler { output_directory, program: Program::new(package_name), program_input: Input::new(), - imported_programs: ImportParser::default(), + asg: None, _engine: PhantomData, _group: PhantomData, } @@ -162,9 +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.parse_program() } /// @@ -189,38 +185,20 @@ 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); + self.program_asg_generate()?; + 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> { + pub(crate) fn program_asg_generate(&mut 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); + let asg = leo_asg::InnerProgram::new(&self.program, &mut leo_imports::ImportParser::default())?; - e - })?; + tracing::debug!("ASG generation complete"); - // 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.asg = Some(asg); Ok(()) } @@ -246,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(()) } @@ -303,13 +274,11 @@ impl> Compiler { pub fn compile_constraints>(self, cs: &mut CS) -> Result { let path = self.main_file_path; - generate_constraints::(cs, &self.program, &self.program_input, &self.imported_programs).map_err( - |mut error| { - error.set_path(&path); + generate_constraints::(cs, self.asg.as_ref().unwrap(), &self.program_input).map_err(|mut error| { + error.set_path(&path); - error - }, - ) + error + }) } /// @@ -317,9 +286,8 @@ impl> Compiler { /// pub fn compile_test_constraints(self, input_pairs: InputPairs) -> Result<(u32, u32), CompilerError> { generate_test_constraints::( - self.program, + self.asg.as_ref().unwrap(), input_pairs, - &self.imported_programs, &self.main_file_path, &self.output_directory, ) @@ -333,12 +301,10 @@ impl> Compiler { cs: &mut CS, ) -> Result { let path = &self.main_file_path; - generate_constraints::<_, G, _>(cs, &self.program, &self.program_input, &self.imported_programs).map_err( - |mut error| { - error.set_path(&path); - error - }, - ) + generate_constraints::<_, G, _>(cs, self.asg.as_ref().unwrap(), &self.program_input).map_err(|mut error| { + error.set_path(&path); + error + }) } } diff --git a/compiler/src/console/assert.rs b/compiler/src/console/assert.rs index e0c0582bbc..38d79ba497 100644 --- a/compiler/src/console/assert.rs +++ b/compiler/src/console/assert.rs @@ -23,7 +23,8 @@ use crate::{ value::ConstrainedValue, GroupType, }; -use leo_ast::{Expression, Span, Type}; +use leo_asg::{Expression, Span}; +use std::sync::Arc; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -34,17 +35,12 @@ impl> ConstrainedProgram { pub fn evaluate_console_assert>( &mut self, cs: &mut CS, - file_scope: &str, - function_scope: &str, indicator: &Boolean, - expression: Expression, + expression: &Arc, span: &Span, ) -> Result<(), ConsoleError> { - let expected_type = Some(Type::Boolean); - let expression_string = expression.to_string(); - // Evaluate assert expression - let assert_expression = self.enforce_expression(cs, file_scope, function_scope, expected_type, expression)?; + let assert_expression = self.enforce_expression(cs, expression)?; // If the indicator bit is false, do not evaluate the assertion // This is okay since we are not enforcing any constraints @@ -57,7 +53,7 @@ impl> ConstrainedProgram { ConstrainedValue::Boolean(boolean) => boolean.get_value(), _ => { return Err(ConsoleError::assertion_must_be_boolean( - expression_string, + span.text.clone(), span.to_owned(), )); } @@ -65,7 +61,7 @@ impl> ConstrainedProgram { let result_bool = result_option.ok_or_else(|| ConsoleError::assertion_depends_on_input(span.to_owned()))?; if !result_bool { - return Err(ConsoleError::assertion_failed(expression_string, span.to_owned())); + return Err(ConsoleError::assertion_failed(span.text.clone(), span.to_owned())); } Ok(()) diff --git a/compiler/src/console/console.rs b/compiler/src/console/console.rs index 0c6ba412e0..ba9b8db271 100644 --- a/compiler/src/console/console.rs +++ b/compiler/src/console/console.rs @@ -17,7 +17,7 @@ //! Evaluates a macro in a compiled Leo program. use crate::{errors::ConsoleError, program::ConstrainedProgram, statement::get_indicator_value, GroupType}; -use leo_ast::{ConsoleFunction, ConsoleStatement}; +use leo_asg::{ConsoleFunction, ConsoleStatement}; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -28,31 +28,29 @@ impl> ConstrainedProgram { pub fn evaluate_console_function_call>( &mut self, cs: &mut CS, - file_scope: &str, - function_scope: &str, indicator: &Boolean, - console: ConsoleStatement, + console: &ConsoleStatement, ) -> Result<(), ConsoleError> { - match console.function { + match &console.function { ConsoleFunction::Assert(expression) => { - self.evaluate_console_assert(cs, file_scope, function_scope, indicator, expression, &console.span)?; + self.evaluate_console_assert(cs, indicator, expression, &console.span.clone().unwrap_or_default())?; } ConsoleFunction::Debug(string) => { - let string = self.format(cs, file_scope, function_scope, string)?; + let string = self.format(cs, string)?; if get_indicator_value(indicator) { tracing::debug!("{}", string); } } ConsoleFunction::Error(string) => { - let string = self.format(cs, file_scope, function_scope, string)?; + let string = self.format(cs, string)?; if get_indicator_value(indicator) { tracing::error!("{}", string); } } ConsoleFunction::Log(string) => { - let string = self.format(cs, file_scope, function_scope, string)?; + let string = self.format(cs, string)?; if get_indicator_value(indicator) { tracing::info!("{}", string); diff --git a/compiler/src/console/format.rs b/compiler/src/console/format.rs index 50b7aec7b9..ee680a77e0 100644 --- a/compiler/src/console/format.rs +++ b/compiler/src/console/format.rs @@ -17,7 +17,7 @@ //! Evaluates a formatted string in a compiled Leo program. use crate::{errors::ConsoleError, program::ConstrainedProgram, GroupType}; -use leo_ast::FormattedString; +use leo_asg::FormattedString; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -28,16 +28,14 @@ impl> ConstrainedProgram { pub fn format>( &mut self, cs: &mut CS, - file_scope: &str, - function_scope: &str, - formatted: FormattedString, + formatted: &FormattedString, ) -> Result { // Check that containers and parameters match if formatted.containers.len() != formatted.parameters.len() { return Err(ConsoleError::length( formatted.containers.len(), formatted.parameters.len(), - formatted.span, + formatted.span.clone(), )); } @@ -51,8 +49,8 @@ impl> ConstrainedProgram { // Insert the parameter for each container `{}` let mut result = string.to_string(); - for parameter in formatted.parameters.into_iter() { - let parameter_value = self.enforce_expression(cs, file_scope, function_scope, None, parameter)?; + for parameter in formatted.parameters.iter() { + let parameter_value = self.enforce_expression(cs, parameter)?; result = result.replacen("{}", ¶meter_value.to_string(), 1); } diff --git a/compiler/src/constraints/constraints.rs b/compiler/src/constraints/constraints.rs index f51464f7f6..6b45a3402e 100644 --- a/compiler/src/constraints/constraints.rs +++ b/compiler/src/constraints/constraints.rs @@ -16,17 +16,9 @@ //! Generates R1CS constraints for a compiled Leo program. -use crate::{ - errors::CompilerError, - new_scope, - ConstrainedProgram, - ConstrainedValue, - GroupType, - OutputBytes, - OutputFile, -}; -use leo_ast::{Input, Program}; -use leo_imports::ImportParser; +use crate::{errors::CompilerError, ConstrainedProgram, GroupType, OutputBytes, OutputFile}; +use leo_asg::Program; +use leo_ast::Input; use leo_input::LeoInputParser; use leo_package::inputs::InputPairs; @@ -40,19 +32,17 @@ pub fn generate_constraints, CS: Constrai cs: &mut CS, program: &Program, input: &Input, - imported_programs: &ImportParser, ) -> Result { - let mut resolved_program = ConstrainedProgram::::new(); - let program_name = program.get_name(); - let main_function_name = new_scope(&program_name, "main"); + let mut resolved_program = ConstrainedProgram::::new(program.clone()); - resolved_program.store_definitions(program, imported_programs)?; + let main = { + let program = program.borrow(); + program.functions.get("main").cloned() + }; - let main = resolved_program.get(&main_function_name).ok_or(CompilerError::NoMain)?; - - match main.clone() { - ConstrainedValue::Function(_circuit_identifier, function) => { - let result = resolved_program.enforce_main_function(cs, &program_name, *function, input)?; + match main { + Some(function) => { + let result = resolved_program.enforce_main_function(cs, &function, input)?; Ok(result) } _ => Err(CompilerError::NoMainFunction), @@ -60,38 +50,34 @@ pub fn generate_constraints, CS: Constrai } pub fn generate_test_constraints>( - program: Program, + program: &Program, input: InputPairs, - imported_programs: &ImportParser, main_file_path: &Path, output_directory: &Path, ) -> Result<(u32, u32), CompilerError> { - let mut resolved_program = ConstrainedProgram::::new(); - let program_name = program.get_name(); - - let tests = program.tests.clone(); - - // Store definitions - resolved_program.store_definitions(&program, imported_programs)?; + let mut resolved_program = ConstrainedProgram::::new(program.clone()); + let program_name = program.borrow().name.clone(); // Get default input let default = input.pairs.get(&program_name); + let program = program.borrow(); + let tests = &program.test_functions; tracing::info!("Running {} tests", tests.len()); // Count passed and failed tests let mut passed = 0; let mut failed = 0; - for (test_name, test) in tests.into_iter() { + for (test_name, (function, input_file)) in tests.into_iter() { let cs = &mut TestConstraintSystem::::new(); let full_test_name = format!("{}::{}", program_name.clone(), test_name); let mut output_file_name = program_name.clone(); // get input file name from annotation or use test_name - let input_pair = match test.input_file { + 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(); @@ -117,10 +103,7 @@ pub fn generate_test_constraints>( // run test function on new program with input let result = resolved_program.enforce_main_function( - cs, - &program_name, - test.function, - &input, // pass program input into every test + cs, function, &input, // pass program input into every test ); match (result.is_ok(), cs.is_satisfied()) { diff --git a/compiler/src/definition/definition.rs b/compiler/src/definition/definition.rs index 3b46f30f79..030b6d654a 100644 --- a/compiler/src/definition/definition.rs +++ b/compiler/src/definition/definition.rs @@ -16,30 +16,19 @@ //! Stores all defined names in a compiled Leo program. -use crate::{ - program::{new_scope, ConstrainedProgram}, - value::ConstrainedValue, - GroupType, -}; -use leo_ast::Identifier; +use crate::{program::ConstrainedProgram, value::ConstrainedValue, GroupType}; +use leo_asg::Variable; use snarkvm_models::curves::{Field, PrimeField}; impl> ConstrainedProgram { - pub fn store_definition( - &mut self, - function_scope: &str, - mutable: bool, - identifier: Identifier, - mut value: ConstrainedValue, - ) { + pub fn store_definition(&mut self, variable: &Variable, mut value: ConstrainedValue) { + let variable = variable.borrow(); // Store with given mutability - if mutable { + if variable.mutable { value = ConstrainedValue::Mutable(Box::new(value)); } - let variable_program_identifier = new_scope(function_scope, &identifier.name); - - self.store(variable_program_identifier, value); + self.store(variable.id, value); } } diff --git a/compiler/src/definition/definitions.rs b/compiler/src/definition/definitions.rs deleted file mode 100644 index 7562f9ce2a..0000000000 --- a/compiler/src/definition/definitions.rs +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (C) 2019-2021 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 . - -//! Stores all defined names in a compiled Leo program. - -use crate::{ - errors::ImportError, - program::{new_scope, ConstrainedProgram}, - value::ConstrainedValue, - GroupType, -}; -use leo_ast::Program; -use leo_imports::ImportParser; - -use snarkvm_models::curves::{Field, PrimeField}; - -impl> ConstrainedProgram { - pub fn store_definitions( - &mut self, - program: &Program, - imported_programs: &ImportParser, - ) -> Result<(), ImportError> { - let program_name = program.name.trim_end_matches(".leo"); - - // evaluate all import statements and store imported definitions - program - .imports - .iter() - .map(|import| self.store_import(&program_name, import, imported_programs)) - .collect::, ImportError>>()?; - - // evaluate and store all circuit definitions - program.circuits.iter().for_each(|(identifier, circuit)| { - let resolved_circuit_name = new_scope(program_name, &identifier.name); - self.store( - resolved_circuit_name, - ConstrainedValue::CircuitDefinition(circuit.clone()), - ); - }); - - // evaluate and store all function definitions - program.functions.iter().for_each(|(function_name, function)| { - let resolved_function_name = new_scope(program_name, &function_name.name); - self.store( - resolved_function_name, - ConstrainedValue::Function(None, Box::new(function.clone())), - ); - }); - - Ok(()) - } -} diff --git a/compiler/src/definition/mod.rs b/compiler/src/definition/mod.rs index 5c4f68da6d..04e8f77665 100644 --- a/compiler/src/definition/mod.rs +++ b/compiler/src/definition/mod.rs @@ -16,6 +16,3 @@ pub mod definition; pub use self::definition::*; - -pub mod definitions; -pub use self::definitions::*; diff --git a/compiler/src/errors/compiler.rs b/compiler/src/errors/compiler.rs index ff433e1301..c8e7b496a9 100644 --- a/compiler/src/errors/compiler.rs +++ b/compiler/src/errors/compiler.rs @@ -15,13 +15,12 @@ // along with the Leo library. If not, see . use crate::errors::{FunctionError, ImportError, OutputBytesError, OutputFileError}; +use leo_asg::AsgConvertError; use leo_ast::AstError; 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}; @@ -74,9 +73,7 @@ pub enum CompilerError { SerdeError(#[from] SerdeError), #[error("{}", _0)] - SymbolTableError(#[from] SymbolTableError), - #[error("{}", _0)] - TypeInferenceError(#[from] TypeInferenceError), + AsgConvertError(#[from] AsgConvertError), } impl CompilerError { @@ -85,8 +82,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/expression.rs b/compiler/src/errors/expression.rs index 05f650e309..38d17fe2e3 100644 --- a/compiler/src/errors/expression.rs +++ b/compiler/src/errors/expression.rs @@ -16,7 +16,6 @@ use crate::errors::{AddressError, BooleanError, FieldError, FunctionError, GroupError, IntegerError, ValueError}; use leo_ast::{ArrayDimensions, Error as FormattedError, Identifier, PositiveNumber, Span}; -use leo_core::LeoCorePackageError; use snarkvm_errors::gadgets::SynthesisError; use std::path::Path; @@ -44,9 +43,6 @@ pub enum ExpressionError { #[error("{}", _0)] IntegerError(#[from] IntegerError), - #[error("{}", _0)] - LeoCoreError(#[from] LeoCorePackageError), - #[error("{}", _0)] ValueError(#[from] ValueError), } @@ -61,7 +57,6 @@ impl ExpressionError { ExpressionError::FunctionError(error) => error.set_path(path), ExpressionError::GroupError(error) => error.set_path(path), ExpressionError::IntegerError(error) => error.set_path(path), - ExpressionError::LeoCoreError(error) => error.set_path(path), ExpressionError::ValueError(error) => error.set_path(path), } } diff --git a/compiler/src/errors/function.rs b/compiler/src/errors/function.rs index d50c9e99c0..3e020d33fd 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/errors/import.rs b/compiler/src/errors/import.rs index 3406ec33e0..74ee48cc83 100644 --- a/compiler/src/errors/import.rs +++ b/compiler/src/errors/import.rs @@ -15,15 +15,11 @@ // along with the Leo library. If not, see . use leo_ast::{Error as FormattedError, Identifier, ImportSymbol, Span}; -use leo_core::LeoCorePackageError; #[derive(Debug, Error)] pub enum ImportError { #[error("{}", _0)] Error(#[from] FormattedError), - - #[error("{}", _0)] - LeoCoreError(#[from] LeoCorePackageError), } impl ImportError { diff --git a/compiler/src/errors/output_bytes.rs b/compiler/src/errors/output_bytes.rs index 3e2b3bc4d4..71649b0910 100644 --- a/compiler/src/errors/output_bytes.rs +++ b/compiler/src/errors/output_bytes.rs @@ -15,7 +15,8 @@ // along with the Leo library. If not, see . use crate::errors::ValueError; -use leo_ast::{Error as FormattedError, Span, Type}; +use leo_asg::{AsgConvertError, Type}; +use leo_ast::{Error as FormattedError, Span}; use std::path::Path; @@ -26,6 +27,9 @@ pub enum OutputBytesError { #[error("{}", _0)] ValueError(#[from] ValueError), + + #[error("{}", _0)] + AsgConvertError(#[from] AsgConvertError), } impl OutputBytesError { @@ -33,6 +37,7 @@ impl OutputBytesError { match self { OutputBytesError::Error(error) => error.set_path(path), OutputBytesError::ValueError(error) => error.set_path(path), + OutputBytesError::AsgConvertError(_error) => (), } } @@ -46,7 +51,7 @@ impl OutputBytesError { Self::new_from_span(message, span) } - pub fn mismatched_output_types(left: Type, right: Type, span: Span) -> Self { + pub fn mismatched_output_types(left: &Type, right: &Type, span: Span) -> Self { let message = format!( "Mismatched types. Expected register output type `{}`, found type `{}`.", left, right diff --git a/compiler/src/errors/statement.rs b/compiler/src/errors/statement.rs index e62d74aed6..d915d40dff 100644 --- a/compiler/src/errors/statement.rs +++ b/compiler/src/errors/statement.rs @@ -15,7 +15,8 @@ // along with the Leo library. If not, see . use crate::errors::{AddressError, BooleanError, ConsoleError, ExpressionError, IntegerError, ValueError}; -use leo_ast::{Error as FormattedError, Span, Type}; +use leo_asg::Type; +use leo_ast::{Error as FormattedError, Span}; use std::path::Path; @@ -166,7 +167,7 @@ impl StatementError { Self::new_from_span(message, span) } - pub fn no_returns(expected: Type, span: Span) -> Self { + pub fn no_returns(expected: &Type, span: Span) -> Self { let message = format!( "function expected `{}` return type but no valid branches returned a result", expected diff --git a/compiler/src/expression/arithmetic/add.rs b/compiler/src/expression/arithmetic/add.rs index e0b21d9da5..b122e9188f 100644 --- a/compiler/src/expression/arithmetic/add.rs +++ b/compiler/src/expression/arithmetic/add.rs @@ -40,14 +40,6 @@ pub fn enforce_add, CS: ConstraintSystem< (ConstrainedValue::Group(point_1), ConstrainedValue::Group(point_2)) => { Ok(ConstrainedValue::Group(point_1.add(cs, &point_2, span)?)) } - (ConstrainedValue::Unresolved(string), val_2) => { - let val_1 = ConstrainedValue::from_other(string, &val_2, span)?; - enforce_add(cs, val_1, val_2, span) - } - (val_1, ConstrainedValue::Unresolved(string)) => { - let val_2 = ConstrainedValue::from_other(string, &val_1, span)?; - enforce_add(cs, val_1, val_2, span) - } (val_1, val_2) => Err(ExpressionError::incompatible_types( format!("{} + {}", val_1, val_2), span.to_owned(), diff --git a/compiler/src/expression/arithmetic/div.rs b/compiler/src/expression/arithmetic/div.rs index 981a165aac..07637c9406 100644 --- a/compiler/src/expression/arithmetic/div.rs +++ b/compiler/src/expression/arithmetic/div.rs @@ -37,14 +37,6 @@ pub fn enforce_div, CS: ConstraintSystem< (ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => { Ok(ConstrainedValue::Field(field_1.div(cs, &field_2, span)?)) } - (ConstrainedValue::Unresolved(string), val_2) => { - let val_1 = ConstrainedValue::from_other(string, &val_2, span)?; - enforce_div(cs, val_1, val_2, span) - } - (val_1, ConstrainedValue::Unresolved(string)) => { - let val_2 = ConstrainedValue::from_other(string, &val_1, span)?; - enforce_div(cs, val_1, val_2, span) - } (val_1, val_2) => Err(ExpressionError::incompatible_types( format!("{} / {}", val_1, val_2,), span.to_owned(), diff --git a/compiler/src/expression/arithmetic/mul.rs b/compiler/src/expression/arithmetic/mul.rs index 7aaa93523d..b959d3c8f0 100644 --- a/compiler/src/expression/arithmetic/mul.rs +++ b/compiler/src/expression/arithmetic/mul.rs @@ -37,14 +37,6 @@ pub fn enforce_mul, CS: ConstraintSystem< (ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => { Ok(ConstrainedValue::Field(field_1.mul(cs, &field_2, span)?)) } - (ConstrainedValue::Unresolved(string), val_2) => { - let val_1 = ConstrainedValue::from_other(string, &val_2, span)?; - enforce_mul(cs, val_1, val_2, span) - } - (val_1, ConstrainedValue::Unresolved(string)) => { - let val_2 = ConstrainedValue::from_other(string, &val_1, span)?; - enforce_mul(cs, val_1, val_2, span) - } (val_1, val_2) => Err(ExpressionError::incompatible_types( format!("{} * {}", val_1, val_2), span.to_owned(), diff --git a/compiler/src/expression/arithmetic/pow.rs b/compiler/src/expression/arithmetic/pow.rs index 5d269ce591..c342704751 100644 --- a/compiler/src/expression/arithmetic/pow.rs +++ b/compiler/src/expression/arithmetic/pow.rs @@ -34,14 +34,6 @@ pub fn enforce_pow, CS: ConstraintSystem< (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { Ok(ConstrainedValue::Integer(num_1.pow(cs, num_2, span)?)) } - (ConstrainedValue::Unresolved(string), val_2) => { - let val_1 = ConstrainedValue::from_other(string, &val_2, span)?; - enforce_pow(cs, val_1, val_2, span) - } - (val_1, ConstrainedValue::Unresolved(string)) => { - let val_2 = ConstrainedValue::from_other(string, &val_1, span)?; - enforce_pow(cs, val_1, val_2, span) - } (val_1, val_2) => Err(ExpressionError::incompatible_types( format!("{} ** {}", val_1, val_2,), span.to_owned(), diff --git a/compiler/src/expression/arithmetic/sub.rs b/compiler/src/expression/arithmetic/sub.rs index e3fa60add2..abe23b64d1 100644 --- a/compiler/src/expression/arithmetic/sub.rs +++ b/compiler/src/expression/arithmetic/sub.rs @@ -40,14 +40,6 @@ pub fn enforce_sub, CS: ConstraintSystem< (ConstrainedValue::Group(point_1), ConstrainedValue::Group(point_2)) => { Ok(ConstrainedValue::Group(point_1.sub(cs, &point_2, span)?)) } - (ConstrainedValue::Unresolved(string), val_2) => { - let val_1 = ConstrainedValue::from_other(string, &val_2, &span)?; - enforce_sub(cs, val_1, val_2, span) - } - (val_1, ConstrainedValue::Unresolved(string)) => { - let val_2 = ConstrainedValue::from_other(string, &val_1, &span)?; - enforce_sub(cs, val_1, val_2, span) - } (val_1, val_2) => Err(ExpressionError::incompatible_types( format!("{} - {}", val_1, val_2), span.to_owned(), diff --git a/compiler/src/expression/array/access.rs b/compiler/src/expression/array/access.rs index 9ee6884bb4..cf2af83ab4 100644 --- a/compiler/src/expression/array/access.rs +++ b/compiler/src/expression/array/access.rs @@ -17,7 +17,8 @@ //! Enforces array access in a compiled Leo program. use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType}; -use leo_ast::{Expression, Span, Type}; +use leo_asg::{Expression, Span}; +use std::sync::Arc; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -29,19 +30,16 @@ impl> ConstrainedProgram { pub fn enforce_array_access>( &mut self, cs: &mut CS, - file_scope: &str, - function_scope: &str, - expected_type: Option, - array: Expression, - index: Expression, + array: &Arc, + index: &Arc, span: &Span, ) -> Result, ExpressionError> { - let array = match self.enforce_operand(cs, file_scope, function_scope, expected_type, array, span)? { + let array = match self.enforce_operand(cs, array)? { ConstrainedValue::Array(array) => array, value => return Err(ExpressionError::undefined_array(value.to_string(), span.to_owned())), }; - let index_resolved = self.enforce_index(cs, file_scope, function_scope, index, span)?; + let index_resolved = self.enforce_index(cs, index, span)?; Ok(array[index_resolved].to_owned()) } @@ -49,25 +47,22 @@ impl> ConstrainedProgram { pub fn enforce_array_range_access>( &mut self, cs: &mut CS, - file_scope: &str, - function_scope: &str, - expected_type: Option, - array: Expression, - left: Option, - right: Option, + array: &Arc, + left: Option<&Arc>, + right: Option<&Arc>, span: &Span, ) -> Result, ExpressionError> { - let array = match self.enforce_operand(cs, file_scope, function_scope, expected_type, array, span)? { + let array = match self.enforce_operand(cs, array)? { ConstrainedValue::Array(array) => array, value => return Err(ExpressionError::undefined_array(value.to_string(), span.to_owned())), }; - let from_resolved = match left { - Some(from_index) => self.enforce_index(cs, file_scope, function_scope, from_index, span)?, + let from_resolved = match left.as_deref() { + Some(from_index) => self.enforce_index(cs, from_index, span)?, None => 0usize, // Array slice starts at index 0 }; - let to_resolved = match right { - Some(to_index) => self.enforce_index(cs, file_scope, function_scope, to_index, span)?, + let to_resolved = match right.as_deref() { + Some(to_index) => self.enforce_index(cs, to_index, span)?, None => array.len(), // Array slice ends at array length }; Ok(ConstrainedValue::Array(array[from_resolved..to_resolved].to_owned())) diff --git a/compiler/src/expression/array/array.rs b/compiler/src/expression/array/array.rs index 079a00ae96..5a2992bdcb 100644 --- a/compiler/src/expression/array/array.rs +++ b/compiler/src/expression/array/array.rs @@ -16,13 +16,9 @@ //! Enforces an array expression in a compiled Leo program. -use crate::{ - errors::ExpressionError, - program::{new_scope, ConstrainedProgram}, - value::ConstrainedValue, - GroupType, -}; -use leo_ast::{ArrayDimensions, Expression, PositiveNumber, Span, SpreadOrExpression, Type}; +use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType}; +use leo_asg::{Expression, Span}; +use std::sync::Arc; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -34,65 +30,21 @@ impl> ConstrainedProgram { pub fn enforce_array>( &mut self, cs: &mut CS, - file_scope: &str, - function_scope: &str, - mut expected_type: Option, - array: Vec, + array: &[(Arc, bool)], span: Span, ) -> Result, ExpressionError> { - let mut expected_dimension = None; - - // Check explicit array type dimension if given - if let Some(type_) = expected_type { - match type_ { - Type::Array(type_, mut dimensions) => { - // Remove the first dimension of the array. - let first = match dimensions.remove_first() { - Some(number) => { - // Parse the array dimension into a `usize`. - parse_index(&number, &span)? - } - None => return Err(ExpressionError::unexpected_array(type_.to_string(), span)), - }; - - // Update the expected dimension to the first dimension. - expected_dimension = Some(first); - - // Update the expected type to a new array type with the first dimension removed. - expected_type = Some(inner_array_type(*type_, dimensions)); - } - ref type_ => { - // Return an error if the expected type is not an array. - return Err(ExpressionError::unexpected_array(type_.to_string(), span)); - } - } - } + let expected_dimension = None; let mut result = vec![]; - for element in array.into_iter() { - match element { - SpreadOrExpression::Spread(spread) => match spread { - Expression::Identifier(identifier) => { - let array_name = new_scope(&function_scope, &identifier.name); - match self.get(&array_name) { - Some(value) => match value { - ConstrainedValue::Array(array) => result.extend(array.clone()), - value => return Err(ExpressionError::invalid_spread(value.to_string(), span)), - }, - None => return Err(ExpressionError::undefined_array(identifier.name, span)), - } - } - value => return Err(ExpressionError::invalid_spread(value.to_string(), span)), - }, - SpreadOrExpression::Expression(expression) => { - result.push(self.enforce_expression( - cs, - file_scope, - function_scope, - expected_type.clone(), - expression, - )?); + for (element, is_spread) in array.iter() { + let element_value = self.enforce_expression(cs, element)?; + if *is_spread { + match element_value { + ConstrainedValue::Array(array) => result.extend(array), + _ => unimplemented!(), // type should already be checked } + } else { + result.push(element_value); } } @@ -114,144 +66,17 @@ impl> ConstrainedProgram { pub fn enforce_array_initializer>( &mut self, cs: &mut CS, - file_scope: &str, - function_scope: &str, - expected_type: Option, - element_expression: Expression, - mut actual_dimensions: ArrayDimensions, - span: Span, + element_expression: &Arc, + actual_size: usize, ) -> Result, ExpressionError> { - // Compare dimensions - // Case 1: expected == actual => enforce expression with array element type - // Case 2: expected first dimension == actual first dimension => enforce expression with updated array type - // Case 3: expected first dimension != actual first dimension => return mismatched dimensions error + let mut value = self.enforce_expression(cs, element_expression)?; - if let Some(Type::Array(type_, mut expected_dimensions)) = expected_type { - if expected_dimensions == actual_dimensions { - // Case 1 - enforce expression with array element type - let mut value = - self.enforce_expression(cs, file_scope, function_scope, Some(*type_), element_expression)?; + // Allocate the array. + let array = vec![value; actual_size]; - // Allocate the array. - while let Some(dimension) = actual_dimensions.remove_last() { - // Parse the dimension into a `usize`. - let dimension_usize = parse_index(&dimension, &span)?; + // Set the array value. + value = ConstrainedValue::Array(array); - // Allocate the array dimension. - let array = vec![value; dimension_usize]; - - // Set the array value. - value = ConstrainedValue::Array(array); - } - - Ok(value) - } else if expected_dimensions.first() == actual_dimensions.first() { - // Case 2 - enforce expression with updated array type. - let dimension = match expected_dimensions.remove_first() { - Some(number) => { - // Parse the array dimension into a `usize`. - parse_index(&number, &span)? - } - None => return Err(ExpressionError::unexpected_array(type_.to_string(), span)), - }; - - // Update the actual array dimensions. - let _first_dimension = actual_dimensions.remove_first(); - - // Update the expected type to a new array type with the first dimension removed. - let expected_expression_type = Some(inner_array_type(*type_, expected_dimensions)); - - // If the expression has more dimensions. - let element_value = match actual_dimensions.first() { - Some(_dimension) => { - // Get the value of the array element as an initializer. - self.enforce_array_initializer( - cs, - file_scope, - function_scope, - expected_expression_type, - element_expression, - actual_dimensions.clone(), - span, - )? - } - None => { - // Get the value of the array element as an expression. - self.enforce_expression( - cs, - file_scope, - function_scope, - expected_expression_type, - element_expression, - )? - } - }; - - // Allocate the array of values. - let array_values = vec![element_value; dimension]; - - // Create a new value with the expected dimension. - Ok(ConstrainedValue::Array(array_values)) - } else { - // Case 3 - return mismatched dimensions error. - Err(ExpressionError::invalid_first_dimension( - expected_dimensions - .first() - .ok_or_else(|| ExpressionError::undefined_first_dimension(span.clone()))?, - actual_dimensions - .first() - .ok_or_else(|| ExpressionError::undefined_first_dimension(span.clone()))?, - span, - )) - } - } else { - // No explicit type given - evaluate array element expression. - let mut value = - self.enforce_expression(cs, file_scope, function_scope, expected_type, element_expression)?; - - // Allocate the array. - while let Some(dimension) = actual_dimensions.remove_last() { - // Parse the dimension into a `usize`. - let dimension_usize = parse_index(&dimension, &span)?; - - // Allocate the array dimension. - let array = vec![value; dimension_usize]; - - // Set the array value. - value = ConstrainedValue::Array(array); - } - - Ok(value) - } - } -} - -/// -/// Returns the index as a usize. -/// -pub fn parse_index(number: &PositiveNumber, span: &Span) -> Result { - number - .value - .parse::() - .map_err(|_| ExpressionError::invalid_index(number.value.to_owned(), span)) -} - -/// -/// Returns the type of the inner array given an array element and array dimensions. -/// -/// If the array has no dimensions, then an inner array does not exist. Simply return the given -/// element type. -/// -/// If the array has dimensions, then an inner array exists. Create a new type for the -/// inner array. The element type of the new array should be the same as the old array. The -/// dimensions of the new array should be the old array dimensions with the first dimension removed. -/// -pub fn inner_array_type(element_type: Type, dimensions: ArrayDimensions) -> Type { - if dimensions.is_empty() { - // The array has one dimension. - element_type - } else { - // The array has multiple dimensions. - Type::Array(Box::new(element_type), dimensions) + Ok(value) } } diff --git a/compiler/src/expression/array/index.rs b/compiler/src/expression/array/index.rs index f59bef1a6a..6d910767a6 100644 --- a/compiler/src/expression/array/index.rs +++ b/compiler/src/expression/array/index.rs @@ -17,7 +17,8 @@ //! Enforces an array index expression in a compiled Leo program. use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType}; -use leo_ast::{Expression, IntegerType, Span, Type}; +use leo_asg::{Expression, Span}; +use std::sync::Arc; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -28,13 +29,10 @@ impl> ConstrainedProgram { pub(crate) fn enforce_index>( &mut self, cs: &mut CS, - file_scope: &str, - function_scope: &str, - index: Expression, + index: &Arc, span: &Span, ) -> Result { - let expected_type = Some(Type::IntegerType(IntegerType::U32)); - match self.enforce_operand(cs, file_scope, function_scope, expected_type, index, &span)? { + match self.enforce_operand(cs, index)? { ConstrainedValue::Integer(number) => Ok(number.to_usize(span)?), value => Err(ExpressionError::invalid_index(value.to_string(), span)), } diff --git a/compiler/src/expression/binary/binary.rs b/compiler/src/expression/binary/binary.rs index 42bf89cf85..15ddc38e70 100644 --- a/compiler/src/expression/binary/binary.rs +++ b/compiler/src/expression/binary/binary.rs @@ -17,7 +17,8 @@ //! Enforces a binary expression in a compiled Leo program. use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType}; -use leo_ast::{Expression, Span, Type}; +use leo_asg::Expression; +use std::sync::Arc; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -31,19 +32,11 @@ impl> ConstrainedProgram { pub fn enforce_binary_expression>( &mut self, cs: &mut CS, - file_scope: &str, - function_scope: &str, - expected_type: Option, - left: Expression, - right: Expression, - span: &Span, + left: &Arc, + right: &Arc, ) -> Result, ExpressionError> { - let mut resolved_left = - self.enforce_operand(cs, file_scope, function_scope, expected_type.clone(), left, span)?; - let mut resolved_right = - self.enforce_operand(cs, file_scope, function_scope, expected_type.clone(), right, span)?; - - resolved_left.resolve_types(&mut resolved_right, expected_type, span)?; + let resolved_left = self.enforce_operand(cs, left)?; + let resolved_right = self.enforce_operand(cs, right)?; Ok((resolved_left, resolved_right)) } diff --git a/compiler/src/expression/binary/operand.rs b/compiler/src/expression/binary/operand.rs index a57d2deb0e..46235d2db5 100644 --- a/compiler/src/expression/binary/operand.rs +++ b/compiler/src/expression/binary/operand.rs @@ -17,7 +17,8 @@ //! Enforces one operand in a binary expression in a compiled Leo program. use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType}; -use leo_ast::{Expression, Span, Type}; +use leo_asg::Expression; +use std::sync::Arc; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -31,16 +32,11 @@ impl> ConstrainedProgram { pub fn enforce_operand>( &mut self, cs: &mut CS, - file_scope: &str, - function_scope: &str, - expected_type: Option, - expression: Expression, - span: &Span, + expression: &Arc, ) -> Result, ExpressionError> { - let mut branch = self.enforce_expression(cs, file_scope, function_scope, expected_type.clone(), expression)?; + let mut branch = self.enforce_expression(cs, expression)?; branch.get_inner_mut(); - branch.resolve_type(expected_type, span)?; Ok(branch) } diff --git a/compiler/src/expression/circuit/access.rs b/compiler/src/expression/circuit/access.rs index 2e2a132b52..7c2b26b6a1 100644 --- a/compiler/src/expression/circuit/access.rs +++ b/compiler/src/expression/circuit/access.rs @@ -16,82 +16,47 @@ //! Enforces a circuit access expression in a compiled Leo program. -use crate::{ - errors::ExpressionError, - program::{new_scope, ConstrainedProgram}, - value::ConstrainedValue, - GroupType, -}; -use leo_ast::{Expression, Identifier, Span, Type}; +use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType}; +use leo_asg::{CircuitAccessExpression, Node}; use snarkvm_models::{ curves::{Field, PrimeField}, gadgets::r1cs::ConstraintSystem, }; -static SELF_KEYWORD: &str = "self"; - impl> ConstrainedProgram { #[allow(clippy::too_many_arguments)] pub fn enforce_circuit_access>( &mut self, cs: &mut CS, - file_scope: &str, - function_scope: &str, - expected_type: Option, - circuit_identifier: Expression, - circuit_member: Identifier, - span: Span, + expr: &CircuitAccessExpression, ) -> Result, ExpressionError> { - // access a circuit member using the `self` keyword - if let Expression::Identifier(ref identifier) = circuit_identifier { - if identifier.is_self() { - let self_file_scope = new_scope(&file_scope, &identifier.name); - let self_function_scope = new_scope(&self_file_scope, &identifier.name); - - let member_value = - self.evaluate_identifier(&self_file_scope, &self_function_scope, None, circuit_member)?; - - return Ok(member_value); - } - } - - let (circuit_name, members) = - match self.enforce_operand(cs, file_scope, function_scope, expected_type, circuit_identifier, &span)? { - ConstrainedValue::CircuitExpression(name, members) => (name, members), - value => return Err(ExpressionError::undefined_circuit(value.to_string(), span)), - }; - - let matched_member = members.clone().into_iter().find(|member| member.0 == circuit_member); - - match matched_member { - Some(member) => { - match &member.1 { - ConstrainedValue::Function(ref _circuit_identifier, ref function) => { - // Check for function input `self` or `mut self`. - if function.contains_self() { - // Pass circuit members into function call by value - for stored_member in members { - let circuit_scope = new_scope(&file_scope, &circuit_name.name); - let self_keyword = new_scope(&circuit_scope, SELF_KEYWORD); - let variable = new_scope(&self_keyword, &stored_member.0.name); - - self.store(variable, stored_member.1.clone()); - } - } + if let Some(target) = &expr.target { + //todo: we can prob pass values by ref here to avoid copying the entire circuit on access + let target_value = self.enforce_operand(cs, target)?; + match target_value { + 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) + } else { + Err(ExpressionError::undefined_member_access( + expr.circuit.name.borrow().to_string(), + expr.member.to_string(), + expr.member.span.clone(), + )) } - ConstrainedValue::Static(value) => { - return Err(ExpressionError::invalid_static_access(value.to_string(), span)); - } - _ => {} } - Ok(member.1) + value => Err(ExpressionError::undefined_circuit( + value.to_string(), + target.span().cloned().unwrap_or_default(), + )), } - None => Err(ExpressionError::undefined_member_access( - circuit_name.to_string(), - circuit_member.to_string(), - span, - )), + } else { + Err(ExpressionError::invalid_static_access( + expr.member.to_string(), + expr.member.span.clone(), + )) } } } diff --git a/compiler/src/expression/circuit/circuit.rs b/compiler/src/expression/circuit/circuit.rs index f561809107..e1862a94af 100644 --- a/compiler/src/expression/circuit/circuit.rs +++ b/compiler/src/expression/circuit/circuit.rs @@ -18,11 +18,11 @@ use crate::{ errors::ExpressionError, - program::{new_scope, ConstrainedProgram}, + program::ConstrainedProgram, value::{ConstrainedCircuitMember, ConstrainedValue}, GroupType, }; -use leo_ast::{CircuitMember, CircuitVariableDefinition, Identifier, Span}; +use leo_asg::{CircuitInitExpression, CircuitMemberBody, Span}; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -33,65 +33,34 @@ impl> ConstrainedProgram { pub fn enforce_circuit>( &mut self, cs: &mut CS, - file_scope: &str, - function_scope: &str, - identifier: Identifier, - members: Vec, - span: Span, + expr: &CircuitInitExpression, + span: &Span, ) -> Result, ExpressionError> { - // Circuit definitions are located at the minimum file scope - let minimum_scope = file_scope.split('_').next().unwrap(); - let identifier_string = identifier.to_string(); - let mut program_identifier = new_scope(minimum_scope, &identifier_string); + let circuit = expr + .circuit + .body + .borrow() + .upgrade() + .expect("circuit init stale circuit ref"); + let members = circuit.members.borrow(); - if identifier.is_self() { - program_identifier = file_scope.to_string(); + let mut resolved_members = Vec::with_capacity(members.len()); + + // type checking is already done in asg + for (name, inner) in expr.values.iter() { + let target = members + .get(&name.name) + .expect("illegal name in asg circuit init expression"); + match target { + CircuitMemberBody::Variable(_type_) => { + let variable_value = self.enforce_expression(cs, inner)?; + resolved_members.push(ConstrainedCircuitMember(name.clone(), variable_value)); + } + _ => return Err(ExpressionError::expected_circuit_member(name.to_string(), span.clone())), + } } - let circuit = match self.get(&program_identifier) { - Some(value) => value.clone().extract_circuit(&span)?, - None => return Err(ExpressionError::undefined_circuit(identifier.to_string(), span)), - }; - - let circuit_identifier = circuit.circuit_name.clone(); - let mut resolved_members = Vec::with_capacity(circuit.members.len()); - - for member in circuit.members.into_iter() { - match member { - CircuitMember::CircuitVariable(identifier, type_) => { - let matched_variable = members - .clone() - .into_iter() - .find(|variable| variable.identifier.eq(&identifier)); - match matched_variable { - Some(variable) => { - // Resolve and enforce circuit variable - let variable_value = self.enforce_expression( - cs, - file_scope, - function_scope, - Some(type_.clone()), - variable.expression, - )?; - - resolved_members.push(ConstrainedCircuitMember(identifier, variable_value)) - } - None => return Err(ExpressionError::expected_circuit_member(identifier.to_string(), span)), - } - } - CircuitMember::CircuitFunction(function) => { - let identifier = function.identifier.clone(); - let constrained_function_value = - ConstrainedValue::Function(Some(circuit_identifier.clone()), Box::new(function)); - - resolved_members.push(ConstrainedCircuitMember(identifier, constrained_function_value)); - } - }; - } - - Ok(ConstrainedValue::CircuitExpression( - circuit_identifier, - resolved_members, - )) + let value = ConstrainedValue::CircuitExpression(circuit.clone(), resolved_members); + Ok(value) } } diff --git a/compiler/src/expression/circuit/mod.rs b/compiler/src/expression/circuit/mod.rs index 90ee5bdad8..321ffea674 100644 --- a/compiler/src/expression/circuit/mod.rs +++ b/compiler/src/expression/circuit/mod.rs @@ -21,6 +21,3 @@ pub use self::access::*; pub mod circuit; pub use self::circuit::*; - -pub mod static_access; -pub use self::static_access::*; diff --git a/compiler/src/expression/circuit/static_access.rs b/compiler/src/expression/circuit/static_access.rs deleted file mode 100644 index cbd2d70a79..0000000000 --- a/compiler/src/expression/circuit/static_access.rs +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (C) 2019-2021 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 . - -//! Enforces a circuit static access expression in a compiled Leo program. - -use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType}; -use leo_ast::{CircuitMember, Expression, Identifier, Span, Type}; - -use snarkvm_models::{ - curves::{Field, PrimeField}, - gadgets::r1cs::ConstraintSystem, -}; - -impl> ConstrainedProgram { - #[allow(clippy::too_many_arguments)] - pub fn enforce_circuit_static_access>( - &mut self, - cs: &mut CS, - file_scope: &str, - function_scope: &str, - expected_type: Option, - circuit_identifier: Expression, - circuit_member: Identifier, - span: Span, - ) -> Result, ExpressionError> { - // Get defined circuit - let circuit = match circuit_identifier { - Expression::Identifier(identifier) => { - // Use the "Self" keyword to access a static circuit function - if identifier.is_self() { - let circuit = self - .get(&file_scope) - .ok_or_else(|| ExpressionError::self_keyword(identifier.span))?; - - circuit.to_owned() - } else { - self.evaluate_identifier(&file_scope, &function_scope, expected_type, identifier)? - } - } - expression => self.enforce_expression(cs, file_scope, function_scope, expected_type, expression)?, - } - .extract_circuit(&span)?; - - // Find static circuit function - let matched_function = circuit.members.into_iter().find(|member| match member { - CircuitMember::CircuitFunction(function) => function.identifier == circuit_member, - _ => false, - }); - - // Return errors if no static function exists - let function = match matched_function { - Some(CircuitMember::CircuitFunction(function)) => function, - _ => { - return Err(ExpressionError::undefined_member_access( - circuit.circuit_name.to_string(), - circuit_member.to_string(), - span, - )); - } - }; - - Ok(ConstrainedValue::Function( - Some(circuit.circuit_name), - Box::new(function), - )) - } -} diff --git a/compiler/src/expression/conditional/conditional.rs b/compiler/src/expression/conditional/conditional.rs index 891a196a4d..b181698d48 100644 --- a/compiler/src/expression/conditional/conditional.rs +++ b/compiler/src/expression/conditional/conditional.rs @@ -17,7 +17,8 @@ //! Enforces a conditional expression in a compiled Leo program. use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType}; -use leo_ast::{Expression, Span, Type}; +use leo_asg::{Expression, Span}; +use std::sync::Arc; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -30,23 +31,19 @@ impl> ConstrainedProgram { pub fn enforce_conditional_expression>( &mut self, cs: &mut CS, - file_scope: &str, - function_scope: &str, - expected_type: Option, - conditional: Expression, - first: Expression, - second: Expression, + conditional: &Arc, + first: &Arc, + second: &Arc, span: &Span, ) -> Result, ExpressionError> { - let conditional_value = - match self.enforce_expression(cs, file_scope, function_scope, Some(Type::Boolean), conditional)? { - ConstrainedValue::Boolean(resolved) => resolved, - value => return Err(ExpressionError::conditional_boolean(value.to_string(), span.to_owned())), - }; + let conditional_value = match self.enforce_expression(cs, conditional)? { + ConstrainedValue::Boolean(resolved) => resolved, + value => return Err(ExpressionError::conditional_boolean(value.to_string(), span.to_owned())), + }; - let first_value = self.enforce_operand(cs, file_scope, function_scope, expected_type.clone(), first, span)?; + let first_value = self.enforce_operand(cs, first)?; - let second_value = self.enforce_operand(cs, file_scope, function_scope, expected_type, second, span)?; + let second_value = self.enforce_operand(cs, second)?; let unique_namespace = cs.ns(|| { format!( diff --git a/compiler/src/expression/expression.rs b/compiler/src/expression/expression.rs index 8abbaec91c..ef7178f15e 100644 --- a/compiler/src/expression/expression.rs +++ b/compiler/src/expression/expression.rs @@ -22,71 +22,49 @@ use crate::{ logical::*, program::ConstrainedProgram, relational::*, - value::{boolean::input::new_bool_constant, implicit::*, ConstrainedValue}, - Address, + resolve_core_circuit, + value::{Address, ConstrainedValue, Integer}, FieldType, GroupType, - Integer, }; -use leo_ast::{expression::*, Expression, Type}; +use leo_asg::{expression::*, ConstValue, Expression, Node}; +use std::sync::Arc; use snarkvm_models::{ curves::{Field, PrimeField}, - gadgets::r1cs::ConstraintSystem, + gadgets::{r1cs::ConstraintSystem, utilities::boolean::Boolean}, }; impl> ConstrainedProgram { pub(crate) fn enforce_expression>( &mut self, cs: &mut CS, - file_scope: &str, - function_scope: &str, - expected_type: Option, - expression: Expression, + expression: &Arc, ) -> Result, ExpressionError> { - match expression { + let span = expression.span().cloned().unwrap_or_default(); + match &**expression { // Variables - Expression::Identifier(unresolved_variable) => { - self.evaluate_identifier(file_scope, function_scope, expected_type, unresolved_variable) - } + Expression::VariableRef(variable_ref) => self.evaluate_ref(variable_ref), // Values - Expression::Value(ValueExpression::Address(address, span)) => { - Ok(ConstrainedValue::Address(Address::constant(address, &span)?)) + Expression::Constant(Constant { value, .. }) => { + Ok(match value { + ConstValue::Address(value) => ConstrainedValue::Address(Address::constant(value.clone(), &span)?), + ConstValue::Boolean(value) => ConstrainedValue::Boolean(Boolean::Constant(*value)), + ConstValue::Field(value) => ConstrainedValue::Field(FieldType::constant(value.to_string(), &span)?), + ConstValue::Group(value) => ConstrainedValue::Group(G::constant(value, &span)?), + ConstValue::Int(value) => ConstrainedValue::Integer(Integer::new(value)), + ConstValue::Tuple(_) | ConstValue::Array(_) => unimplemented!(), // shouldnt be in the asg here + }) } - Expression::Value(ValueExpression::Boolean(boolean, span)) => { - Ok(ConstrainedValue::Boolean(new_bool_constant(boolean, &span)?)) - } - Expression::Value(ValueExpression::Field(field, span)) => { - Ok(ConstrainedValue::Field(FieldType::constant(field, &span)?)) - } - Expression::Value(ValueExpression::Group(group_element)) => { - Ok(ConstrainedValue::Group(G::constant(*group_element)?)) - } - Expression::Value(ValueExpression::Implicit(value, span)) => { - Ok(enforce_number_implicit(expected_type, value, &span)?) - } - Expression::Value(ValueExpression::Integer(type_, integer, span)) => Ok(ConstrainedValue::Integer( - Integer::new(expected_type, &type_, integer, &span)?, - )), // Binary operations - Expression::Binary(BinaryExpression { left, right, op, span }) => { - let (resolved_left, resolved_right) = self.enforce_binary_expression( - cs, - file_scope, - function_scope, - if op.class() == BinaryOperationClass::Numeric { - expected_type - } else { - None - }, - *left, - *right, - &span, - )?; + Expression::Binary(BinaryExpression { + left, right, operation, .. + }) => { + let (resolved_left, resolved_right) = self.enforce_binary_expression(cs, left, right)?; - match op { + match operation { BinaryOperation::Add => enforce_add(cs, resolved_left, resolved_right, &span), BinaryOperation::Sub => enforce_sub(cs, resolved_left, resolved_right, &span), BinaryOperation::Mul => enforce_mul(cs, resolved_left, resolved_right, &span), @@ -99,7 +77,7 @@ impl> ConstrainedProgram { enforce_and(cs, resolved_left, resolved_right, &span).map_err(ExpressionError::BooleanError) } BinaryOperation::Eq => evaluate_eq(cs, resolved_left, resolved_right, &span), - BinaryOperation::Ne => evaluate_not(evaluate_eq(cs, resolved_left, resolved_right, &span)?, span) + BinaryOperation::Ne => evaluate_not(evaluate_eq(cs, resolved_left, resolved_right, &span)?, &span) .map_err(ExpressionError::BooleanError), BinaryOperation::Ge => evaluate_ge(cs, resolved_left, resolved_right, &span), BinaryOperation::Gt => evaluate_gt(cs, resolved_left, resolved_right, &span), @@ -109,114 +87,71 @@ impl> ConstrainedProgram { } // Unary operations - Expression::Unary(UnaryExpression { inner, op, span }) => match op { + Expression::Unary(UnaryExpression { inner, operation, .. }) => match operation { UnaryOperation::Negate => { - let resolved_inner = - self.enforce_expression(cs, file_scope, function_scope, expected_type, *inner)?; + let resolved_inner = self.enforce_expression(cs, inner)?; enforce_negate(cs, resolved_inner, &span) } - UnaryOperation::Not => Ok(evaluate_not( - self.enforce_operand(cs, file_scope, function_scope, expected_type, *inner, &span)?, - span, - )?), + UnaryOperation::Not => Ok(evaluate_not(self.enforce_operand(cs, inner)?, &span)?), }, Expression::Ternary(TernaryExpression { condition, if_true, if_false, - span, - }) => self.enforce_conditional_expression( - cs, - file_scope, - function_scope, - expected_type, - *condition, - *if_true, - *if_false, - &span, - ), + .. + }) => self.enforce_conditional_expression(cs, condition, if_true, if_false, &span), // Arrays - Expression::ArrayInline(ArrayInlineExpression { elements, span }) => { - self.enforce_array(cs, file_scope, function_scope, expected_type, elements, span) + Expression::ArrayInline(ArrayInlineExpression { elements, .. }) => self.enforce_array(cs, elements, span), + Expression::ArrayInit(ArrayInitExpression { element, len, .. }) => { + self.enforce_array_initializer(cs, element, *len) } - Expression::ArrayInit(ArrayInitExpression { - element, - dimensions, - span, - }) => self.enforce_array_initializer( - cs, - file_scope, - function_scope, - expected_type, - *element, - dimensions, - span, - ), - Expression::ArrayAccess(ArrayAccessExpression { array, index, span }) => { - self.enforce_array_access(cs, file_scope, function_scope, expected_type, *array, *index, &span) + Expression::ArrayAccess(ArrayAccessExpression { array, index, .. }) => { + self.enforce_array_access(cs, array, index, &span) + } + Expression::ArrayRangeAccess(ArrayRangeAccessExpression { array, left, right, .. }) => { + self.enforce_array_range_access(cs, array, left.as_ref(), right.as_ref(), &span) } - Expression::ArrayRangeAccess(ArrayRangeAccessExpression { - array, - left, - right, - span, - }) => self.enforce_array_range_access( - cs, - file_scope, - function_scope, - expected_type, - *array, - left.map(|x| *x), - right.map(|x| *x), - &span, - ), // Tuples - Expression::TupleInit(TupleInitExpression { elements, span }) => { - self.enforce_tuple(cs, file_scope, function_scope, expected_type, elements, span) - } - Expression::TupleAccess(TupleAccessExpression { tuple, index, span }) => { - self.enforce_tuple_access(cs, file_scope, function_scope, expected_type, *tuple, index, &span) + Expression::TupleInit(TupleInitExpression { elements, .. }) => self.enforce_tuple(cs, elements), + Expression::TupleAccess(TupleAccessExpression { tuple_ref, index, .. }) => { + self.enforce_tuple_access(cs, tuple_ref, *index, &span) } // Circuits - Expression::CircuitInit(CircuitInitExpression { name, members, span }) => { - self.enforce_circuit(cs, file_scope, function_scope, name, members, span) - } - Expression::CircuitMemberAccess(CircuitMemberAccessExpression { circuit, name, span }) => { - self.enforce_circuit_access(cs, file_scope, function_scope, expected_type, *circuit, name, span) - } - Expression::CircuitStaticFunctionAccess(CircuitStaticFunctionAccessExpression { circuit, name, span }) => { - self.enforce_circuit_static_access(cs, file_scope, function_scope, expected_type, *circuit, name, span) - } + Expression::CircuitInit(expr) => self.enforce_circuit(cs, expr, &span), + Expression::CircuitAccess(expr) => self.enforce_circuit_access(cs, expr), // Functions Expression::Call(CallExpression { function, + target, arguments, - span, - }) => match *function { - Expression::Identifier(id) if id.is_core() => self.enforce_core_circuit_call_expression( - cs, - file_scope, - function_scope, - expected_type, - id.name, - arguments, - span, - ), - function => self.enforce_function_call_expression( - cs, - file_scope, - function_scope, - expected_type, - function, - arguments, - span, - ), - }, + .. + }) => { + if let Some(circuit) = function + .circuit + .borrow() + .as_ref() + .map(|x| x.upgrade().expect("stale circuit for member function")) + { + let core_mapping = circuit.core_mapping.borrow(); + if let Some(core_mapping) = core_mapping.as_deref() { + let core_circuit = resolve_core_circuit::(core_mapping); + return self.enforce_core_circuit_call_expression( + cs, + &core_circuit, + &function, + target.as_ref(), + arguments, + &span, + ); + } + } + self.enforce_function_call_expression(cs, &function, target.as_ref(), arguments, &span) + } } } } diff --git a/compiler/src/expression/function/core_circuit.rs b/compiler/src/expression/function/core_circuit.rs index 889f4cfb12..f0d88c94b7 100644 --- a/compiler/src/expression/function/core_circuit.rs +++ b/compiler/src/expression/function/core_circuit.rs @@ -13,61 +13,48 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::{program::ConstrainedProgram, value::ConstrainedValue, GroupType}; +use crate::{program::ConstrainedProgram, value::ConstrainedValue, CoreCircuit, GroupType}; -use crate::errors::{ExpressionError, FunctionError}; -use leo_ast::{Expression, Span, Type}; -use leo_core::call_core_circuit; +use crate::errors::ExpressionError; +use leo_asg::{Expression, Function, Span}; use snarkvm_models::{ curves::{Field, PrimeField}, gadgets::r1cs::ConstraintSystem, }; +use std::sync::Arc; impl> ConstrainedProgram { /// Call a default core circuit function with arguments #[allow(clippy::too_many_arguments)] - pub fn enforce_core_circuit_call_expression>( + pub fn enforce_core_circuit_call_expression, C: CoreCircuit>( &mut self, cs: &mut CS, - file_scope: &str, - function_scope: &str, - expected_type: Option, - core_circuit: String, - arguments: Vec, - span: Span, + core_circuit: &C, + function: &Arc, + target: Option<&Arc>, + arguments: &[Arc], + span: &Span, ) -> Result, ExpressionError> { - // Get the value of each core function argument - let mut argument_values = Vec::with_capacity(arguments.len()); - for argument in arguments.into_iter() { - let argument_value = self.enforce_expression(cs, file_scope, function_scope, None, argument)?; - let core_function_argument = argument_value.to_value(); + let function = function + .body + .borrow() + .upgrade() + .expect("stale function in call expression"); - argument_values.push(core_function_argument); - } - - // Call the core function in `leo-core` - let res = call_core_circuit(cs, core_circuit, argument_values, span.clone())?; - - // Convert the core function returns into constrained values - let returns = res.into_iter().map(ConstrainedValue::from).collect::>(); - - let return_value = if returns.len() == 1 { - // The function has a single return - returns[0].clone() + let target_value = if let Some(target) = target { + Some(self.enforce_expression(cs, target)?) } else { - // The function has multiple returns - ConstrainedValue::Tuple(returns) + None }; - // Check that function returns expected type - if let Some(expected) = expected_type { - let actual = return_value.to_type(&span)?; - if expected.ne(&actual) { - return Err(ExpressionError::FunctionError(Box::new( - FunctionError::return_argument_type(expected.to_string(), actual.to_string(), span), - ))); - } - } + // Get the value of each core function argument + let arguments = arguments + .iter() + .map(|argument| self.enforce_expression(cs, argument)) + .collect::, _>>()?; + + // Call the core function + let return_value = core_circuit.call_function(cs, function, span, target_value, arguments)?; Ok(return_value) } diff --git a/compiler/src/expression/function/function.rs b/compiler/src/expression/function/function.rs index 2da8504a5b..c6011eb112 100644 --- a/compiler/src/expression/function/function.rs +++ b/compiler/src/expression/function/function.rs @@ -16,8 +16,9 @@ //! Enforce a function call expression in a compiled Leo program. -use crate::{errors::ExpressionError, new_scope, program::ConstrainedProgram, value::ConstrainedValue, GroupType}; -use leo_ast::{expression::CircuitMemberAccessExpression, Expression, Span, Type}; +use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType}; +use leo_asg::{Expression, Function, Span}; +use std::sync::Arc; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -29,51 +30,29 @@ impl> ConstrainedProgram { pub fn enforce_function_call_expression>( &mut self, cs: &mut CS, - file_scope: &str, - function_scope: &str, - expected_type: Option, - function: Expression, - arguments: Vec, - span: Span, + function: &Arc, + target: Option<&Arc>, + arguments: &[Arc], + span: &Span, ) -> Result, ExpressionError> { - let (declared_circuit_reference, function_value) = match function { - Expression::CircuitMemberAccess(CircuitMemberAccessExpression { circuit, name, span }) => { - // Call a circuit function that can mutate self. - - // Save a reference to the circuit we are mutating. - let circuit_id_string = circuit.to_string(); - let declared_circuit_reference = new_scope(function_scope, &circuit_id_string); - - ( - declared_circuit_reference, - self.enforce_circuit_access(cs, file_scope, function_scope, expected_type, *circuit, name, span)?, - ) - } - function => ( - function_scope.to_string(), - self.enforce_expression(cs, file_scope, function_scope, expected_type, function)?, - ), - }; - - let (outer_scope, function_call) = function_value.extract_function(file_scope, &span)?; - let name_unique = || { format!( "function call {} {}:{}", - function_call.get_name(), + function.name.borrow().clone(), span.line, span.start, ) }; + let function = function + .body + .borrow() + .upgrade() + .expect("stale function in call expression"); - self.enforce_function( - &mut cs.ns(name_unique), - &outer_scope, - function_scope, - function_call, - arguments, - &declared_circuit_reference, - ) - .map_err(|error| ExpressionError::from(Box::new(error))) + let return_value = self + .enforce_function(&mut cs.ns(name_unique), &function, target, arguments) + .map_err(|error| ExpressionError::from(Box::new(error)))?; + + Ok(return_value) } } diff --git a/compiler/src/expression/identifier/identifier.rs b/compiler/src/expression/identifier/identifier.rs deleted file mode 100644 index 3184e20309..0000000000 --- a/compiler/src/expression/identifier/identifier.rs +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (C) 2019-2021 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 . - -//! Enforces an identifier expression in a compiled Leo program. - -use crate::{ - errors::ExpressionError, - program::{new_scope, ConstrainedProgram}, - value::ConstrainedValue, - Address, - GroupType, -}; -use leo_ast::{Identifier, Type}; - -use snarkvm_models::curves::{Field, PrimeField}; - -impl> ConstrainedProgram { - /// Enforce a variable expression by getting the resolved value - pub fn evaluate_identifier( - &mut self, - file_scope: &str, - function_scope: &str, - expected_type: Option, - unresolved_identifier: Identifier, - ) -> Result, ExpressionError> { - // Evaluate the identifier name in the current function scope - let variable_name = new_scope(function_scope, &unresolved_identifier.name); - let identifier_name = new_scope(file_scope, &unresolved_identifier.name); - - let mut result_value = if let Some(value) = self.get(&variable_name) { - // Reassigning variable to another variable - value.clone() - } else if let Some(value) = self.get(&identifier_name) { - // Check global scope (function and circuit names) - value.clone() - } else if let Some(value) = self.get(&unresolved_identifier.name) { - // Check imported file scope - value.clone() - } else if expected_type == Some(Type::Address) { - // If we expect an address type, try to return an address - let address = Address::constant(unresolved_identifier.name, &unresolved_identifier.span)?; - - return Ok(ConstrainedValue::Address(address)); - } else { - return Err(ExpressionError::undefined_identifier(unresolved_identifier)); - }; - - result_value.resolve_type(expected_type, &unresolved_identifier.span)?; - - Ok(result_value) - } -} diff --git a/compiler/src/expression/logical/and.rs b/compiler/src/expression/logical/and.rs index 299891d555..142cb08d6b 100644 --- a/compiler/src/expression/logical/and.rs +++ b/compiler/src/expression/logical/and.rs @@ -17,7 +17,7 @@ //! Enforces a logical `&&` operator in a resolved Leo program. use crate::{errors::BooleanError, value::ConstrainedValue, GroupType}; -use leo_ast::Span; +use leo_asg::Span; use snarkvm_models::{ curves::{Field, PrimeField}, diff --git a/compiler/src/expression/logical/not.rs b/compiler/src/expression/logical/not.rs index 0f362126eb..a4f8ba2ce5 100644 --- a/compiler/src/expression/logical/not.rs +++ b/compiler/src/expression/logical/not.rs @@ -17,16 +17,16 @@ //! Enforces a logical `!` operator in a resolved Leo program. use crate::{errors::BooleanError, value::ConstrainedValue, GroupType}; -use leo_ast::Span; +use leo_asg::Span; use snarkvm_models::curves::{Field, PrimeField}; pub fn evaluate_not>( value: ConstrainedValue, - span: Span, + span: &Span, ) -> Result, BooleanError> { match value { ConstrainedValue::Boolean(boolean) => Ok(ConstrainedValue::Boolean(boolean.not())), - value => Err(BooleanError::cannot_evaluate(format!("!{}", value), span)), + value => Err(BooleanError::cannot_evaluate(format!("!{}", value), span.clone())), } } diff --git a/compiler/src/expression/logical/or.rs b/compiler/src/expression/logical/or.rs index 9d4be1e1ca..ed7876d994 100644 --- a/compiler/src/expression/logical/or.rs +++ b/compiler/src/expression/logical/or.rs @@ -17,7 +17,7 @@ //! Enforces a logical `||` operator in a resolved Leo program. use crate::{errors::BooleanError, value::ConstrainedValue, GroupType}; -use leo_ast::Span; +use leo_asg::Span; use snarkvm_models::{ curves::{Field, PrimeField}, diff --git a/compiler/src/expression/mod.rs b/compiler/src/expression/mod.rs index 2e6d5eab08..77de89cff7 100644 --- a/compiler/src/expression/mod.rs +++ b/compiler/src/expression/mod.rs @@ -37,8 +37,8 @@ pub use self::expression::*; pub mod function; pub use self::function::*; -pub mod identifier; -pub use self::identifier::*; +pub mod variable_ref; +pub use self::variable_ref::*; pub mod logical; pub use self::logical::*; diff --git a/compiler/src/expression/relational/eq.rs b/compiler/src/expression/relational/eq.rs index 6674af0c41..1a1e215879 100644 --- a/compiler/src/expression/relational/eq.rs +++ b/compiler/src/expression/relational/eq.rs @@ -17,7 +17,7 @@ //! Enforces a relational `==` operator in a resolved Leo program. use crate::{enforce_and, errors::ExpressionError, value::ConstrainedValue, GroupType}; -use leo_ast::Span; +use leo_asg::Span; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -74,16 +74,6 @@ pub fn evaluate_eq, CS: ConstraintSystem< } return Ok(current); } - (ConstrainedValue::Unresolved(string), val_2) => { - let mut unique_namespace = cs.ns(|| namespace_string); - let val_1 = ConstrainedValue::from_other(string, &val_2, span)?; - return evaluate_eq(&mut unique_namespace, val_1, val_2, span); - } - (val_1, ConstrainedValue::Unresolved(string)) => { - let mut unique_namespace = cs.ns(|| namespace_string); - let val_2 = ConstrainedValue::from_other(string, &val_1, span)?; - return evaluate_eq(&mut unique_namespace, val_1, val_2, span); - } (val_1, val_2) => { return Err(ExpressionError::incompatible_types( format!("{} == {}", val_1, val_2,), diff --git a/compiler/src/expression/relational/ge.rs b/compiler/src/expression/relational/ge.rs index 92be95a607..5f5ef8fa73 100644 --- a/compiler/src/expression/relational/ge.rs +++ b/compiler/src/expression/relational/ge.rs @@ -17,7 +17,7 @@ //! Enforces a relational `>=` operator in a resolved Leo program. use crate::{errors::ExpressionError, value::ConstrainedValue, GroupType}; -use leo_ast::Span; +use leo_asg::Span; use leo_gadgets::bits::ComparatorGadget; use snarkvm_models::{ @@ -31,19 +31,11 @@ pub fn evaluate_ge, CS: ConstraintSystem< right: ConstrainedValue, span: &Span, ) -> Result, ExpressionError> { - let mut unique_namespace = cs.ns(|| format!("evaluate {} >= {} {}:{}", left, right, span.line, span.start)); + let unique_namespace = cs.ns(|| format!("evaluate {} >= {} {}:{}", left, right, span.line, span.start)); let constraint_result = match (left, right) { (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { num_1.greater_than_or_equal(unique_namespace, &num_2) } - (ConstrainedValue::Unresolved(string), val_2) => { - let val_1 = ConstrainedValue::from_other(string, &val_2, span)?; - return evaluate_ge(&mut unique_namespace, val_1, val_2, span); - } - (val_1, ConstrainedValue::Unresolved(string)) => { - let val_2 = ConstrainedValue::from_other(string, &val_1, span)?; - return evaluate_ge(&mut unique_namespace, val_1, val_2, span); - } (val_1, val_2) => { return Err(ExpressionError::incompatible_types( format!("{} >= {}", val_1, val_2), diff --git a/compiler/src/expression/relational/gt.rs b/compiler/src/expression/relational/gt.rs index b78a984cf1..2d6978bf85 100644 --- a/compiler/src/expression/relational/gt.rs +++ b/compiler/src/expression/relational/gt.rs @@ -17,7 +17,7 @@ //! Enforces a relational `>` operator in a resolved Leo program. use crate::{errors::ExpressionError, value::ConstrainedValue, GroupType}; -use leo_ast::Span; +use leo_asg::Span; use leo_gadgets::bits::ComparatorGadget; use snarkvm_models::{ @@ -31,19 +31,11 @@ pub fn evaluate_gt, CS: ConstraintSystem< right: ConstrainedValue, span: &Span, ) -> Result, ExpressionError> { - let mut unique_namespace = cs.ns(|| format!("evaluate {} > {} {}:{}", left, right, span.line, span.start)); + let unique_namespace = cs.ns(|| format!("evaluate {} > {} {}:{}", left, right, span.line, span.start)); let constraint_result = match (left, right) { (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { num_1.greater_than(unique_namespace, &num_2) } - (ConstrainedValue::Unresolved(string), val_2) => { - let val_1 = ConstrainedValue::from_other(string, &val_2, span)?; - return evaluate_gt(&mut unique_namespace, val_1, val_2, span); - } - (val_1, ConstrainedValue::Unresolved(string)) => { - let val_2 = ConstrainedValue::from_other(string, &val_1, span)?; - return evaluate_gt(&mut unique_namespace, val_1, val_2, span); - } (val_1, val_2) => { return Err(ExpressionError::incompatible_types( format!("{} > {}", val_1, val_2), diff --git a/compiler/src/expression/relational/le.rs b/compiler/src/expression/relational/le.rs index 5cde657024..8e20e753e7 100644 --- a/compiler/src/expression/relational/le.rs +++ b/compiler/src/expression/relational/le.rs @@ -17,7 +17,7 @@ //! Enforces a relational `<=` operator in a resolved Leo program. use crate::{errors::ExpressionError, value::ConstrainedValue, GroupType}; -use leo_ast::Span; +use leo_asg::Span; use leo_gadgets::bits::ComparatorGadget; use snarkvm_models::{ @@ -31,19 +31,11 @@ pub fn evaluate_le, CS: ConstraintSystem< right: ConstrainedValue, span: &Span, ) -> Result, ExpressionError> { - let mut unique_namespace = cs.ns(|| format!("evaluate {} <= {} {}:{}", left, right, span.line, span.start)); + let unique_namespace = cs.ns(|| format!("evaluate {} <= {} {}:{}", left, right, span.line, span.start)); let constraint_result = match (left, right) { (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { num_1.less_than_or_equal(unique_namespace, &num_2) } - (ConstrainedValue::Unresolved(string), val_2) => { - let val_1 = ConstrainedValue::from_other(string, &val_2, span)?; - return evaluate_le(&mut unique_namespace, val_1, val_2, span); - } - (val_1, ConstrainedValue::Unresolved(string)) => { - let val_2 = ConstrainedValue::from_other(string, &val_1, span)?; - return evaluate_le(&mut unique_namespace, val_1, val_2, span); - } (val_1, val_2) => { return Err(ExpressionError::incompatible_types( format!("{} <= {}", val_1, val_2), diff --git a/compiler/src/expression/relational/lt.rs b/compiler/src/expression/relational/lt.rs index 03012ab749..6c68456ac3 100644 --- a/compiler/src/expression/relational/lt.rs +++ b/compiler/src/expression/relational/lt.rs @@ -17,7 +17,7 @@ //! Enforces a relational `<` operator in a resolved Leo program. use crate::{errors::ExpressionError, value::ConstrainedValue, GroupType}; -use leo_ast::Span; +use leo_asg::Span; use leo_gadgets::bits::comparator::EvaluateLtGadget; use snarkvm_models::{ @@ -31,19 +31,11 @@ pub fn evaluate_lt, CS: ConstraintSystem< right: ConstrainedValue, span: &Span, ) -> Result, ExpressionError> { - let mut unique_namespace = cs.ns(|| format!("evaluate {} < {} {}:{}", left, right, span.line, span.start)); + let unique_namespace = cs.ns(|| format!("evaluate {} < {} {}:{}", left, right, span.line, span.start)); let constraint_result = match (left, right) { (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { num_1.less_than(unique_namespace, &num_2) } - (ConstrainedValue::Unresolved(string), val_2) => { - let val_1 = ConstrainedValue::from_other(string, &val_2, span)?; - return evaluate_lt(&mut unique_namespace, val_1, val_2, span); - } - (val_1, ConstrainedValue::Unresolved(string)) => { - let val_2 = ConstrainedValue::from_other(string, &val_1, span)?; - return evaluate_lt(&mut unique_namespace, val_1, val_2, span); - } (val_1, val_2) => { return Err(ExpressionError::incompatible_types( format!("{} < {}", val_1, val_2), diff --git a/compiler/src/expression/tuple/access.rs b/compiler/src/expression/tuple/access.rs index 5134b14576..be8775ea77 100644 --- a/compiler/src/expression/tuple/access.rs +++ b/compiler/src/expression/tuple/access.rs @@ -16,8 +16,9 @@ //! Enforces array access in a compiled Leo program. -use crate::{errors::ExpressionError, parse_index, program::ConstrainedProgram, value::ConstrainedValue, GroupType}; -use leo_ast::{Expression, PositiveNumber, Span, Type}; +use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType}; +use leo_asg::{Expression, Span}; +use std::sync::Arc; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -29,27 +30,22 @@ impl> ConstrainedProgram { pub fn enforce_tuple_access>( &mut self, cs: &mut CS, - file_scope: &str, - function_scope: &str, - expected_type: Option, - tuple: Expression, - index: PositiveNumber, + tuple: &Arc, + index: usize, span: &Span, ) -> Result, ExpressionError> { // Get the tuple values. - let tuple = match self.enforce_operand(cs, file_scope, function_scope, expected_type, tuple, &span)? { + let tuple = match self.enforce_operand(cs, tuple)? { ConstrainedValue::Tuple(tuple) => tuple, value => return Err(ExpressionError::undefined_array(value.to_string(), span.to_owned())), }; - // Parse the tuple index. - let index_usize = parse_index(&index, &span)?; - // Check for out of bounds access. - if index_usize > tuple.len() - 1 { - return Err(ExpressionError::index_out_of_bounds(index_usize, span.to_owned())); + if index > tuple.len() - 1 { + // probably safe to be a panic here + return Err(ExpressionError::index_out_of_bounds(index, span.to_owned())); } - Ok(tuple[index_usize].to_owned()) + Ok(tuple[index].to_owned()) } } diff --git a/compiler/src/expression/tuple/tuple.rs b/compiler/src/expression/tuple/tuple.rs index a04a0aa229..f4520d9070 100644 --- a/compiler/src/expression/tuple/tuple.rs +++ b/compiler/src/expression/tuple/tuple.rs @@ -17,7 +17,8 @@ //! Enforces an tuple expression in a compiled Leo program. use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType}; -use leo_ast::{Expression, Span, Type}; +use leo_asg::Expression; +use std::sync::Arc; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -29,38 +30,11 @@ impl> ConstrainedProgram { pub fn enforce_tuple>( &mut self, cs: &mut CS, - file_scope: &str, - function_scope: &str, - expected_type: Option, - tuple: Vec, - span: Span, + tuple: &[Arc], ) -> Result, ExpressionError> { - // Check explicit tuple type dimension if given - let mut expected_types = vec![]; - - match expected_type { - Some(Type::Tuple(ref types)) => { - expected_types = types.clone(); - } - Some(ref type_) => { - return Err(ExpressionError::unexpected_tuple( - type_.to_string(), - format!("{:?}", tuple), - span, - )); - } - None => {} - } - let mut result = Vec::with_capacity(tuple.len()); - for (i, expression) in tuple.into_iter().enumerate() { - let type_ = if expected_types.is_empty() { - None - } else { - Some(expected_types[i].clone()) - }; - - result.push(self.enforce_expression(cs, file_scope, function_scope, type_, expression)?); + for expression in tuple.iter() { + result.push(self.enforce_expression(cs, expression)?); } Ok(ConstrainedValue::Tuple(result)) diff --git a/compiler/src/expression/identifier/mod.rs b/compiler/src/expression/variable_ref/mod.rs similarity index 93% rename from compiler/src/expression/identifier/mod.rs rename to compiler/src/expression/variable_ref/mod.rs index 56b8007a80..d674eb1d50 100644 --- a/compiler/src/expression/identifier/mod.rs +++ b/compiler/src/expression/variable_ref/mod.rs @@ -16,5 +16,5 @@ //! Methods to enforce identifier expressions in a compiled Leo program. -pub mod identifier; -pub use self::identifier::*; +pub mod variable_ref; +pub use self::variable_ref::*; diff --git a/compiler/src/import/store/core_package.rs b/compiler/src/expression/variable_ref/variable_ref.rs similarity index 52% rename from compiler/src/import/store/core_package.rs rename to compiler/src/expression/variable_ref/variable_ref.rs index b566ffc604..2cfac36ad3 100644 --- a/compiler/src/import/store/core_package.rs +++ b/compiler/src/expression/variable_ref/variable_ref.rs @@ -14,27 +14,24 @@ // 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; +//! Enforces an identifier expression in a compiled Leo program. + +use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType}; +use leo_asg::VariableRef; -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)?; + /// Enforce a variable expression by getting the resolved value + pub fn evaluate_ref(&mut self, variable_ref: &VariableRef) -> Result, ExpressionError> { + // Evaluate the identifier name in the current function scope + let variable = variable_ref.variable.borrow(); + let result_value = if let Some(value) = self.get(&variable.id) { + value.clone() + } else { + return Err(ExpressionError::undefined_identifier(variable.name.clone())); // todo: probably can be a panic here instead + }; - // 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(()) + Ok(result_value) } } diff --git a/compiler/src/function/function.rs b/compiler/src/function/function.rs index 18b1cbf68d..f0fb879448 100644 --- a/compiler/src/function/function.rs +++ b/compiler/src/function/function.rs @@ -16,14 +16,10 @@ //! Enforces constraints on a function in a compiled Leo program. -use crate::{ - errors::FunctionError, - program::{new_scope, ConstrainedProgram}, - value::ConstrainedValue, - GroupType, -}; +use crate::{errors::FunctionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType}; -use leo_ast::{Expression, Function, FunctionInput}; +use leo_asg::{Expression, FunctionBody, FunctionQualifier}; +use std::sync::Arc; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -34,83 +30,77 @@ impl> ConstrainedProgram { pub(crate) fn enforce_function>( &mut self, cs: &mut CS, - scope: &str, - caller_scope: &str, - function: Function, - input: Vec, - declared_circuit_reference: &str, + function: &Arc, + target: Option<&Arc>, + arguments: &[Arc], ) -> Result, FunctionError> { - let function_name = new_scope(scope, function.get_name()); + let target_value = if let Some(target) = target { + Some(self.enforce_expression(cs, target)?) + } else { + None + }; - // Store if function contains input `mut self`. - let mut_self = function.contains_mut_self(); + let self_var = if let Some(target) = &target_value { + let self_var = function + .scope + .borrow() + .resolve_variable("self") + .expect("attempted to call static function from non-static context"); + self.store(self_var.borrow().id, target.clone()); + Some(self_var) + } else { + None + }; + + if function.arguments.len() != arguments.len() { + 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 (input_model, input_expression) in function.filter_self_inputs().zip(input.into_iter()) { - let (name, value) = match input_model { - FunctionInput::InputKeyword(keyword) => { - let value = - self.enforce_function_input(cs, scope, caller_scope, &function_name, None, input_expression)?; + for (variable, input_expression) in function.arguments.iter().zip(arguments.iter()) { + let mut input_value = self.enforce_expression(cs, input_expression)?; + let variable = variable.borrow(); - (keyword.to_string(), value) - } - FunctionInput::SelfKeyword(keyword) => { - let value = - self.enforce_function_input(cs, scope, caller_scope, &function_name, None, input_expression)?; + if variable.mutable { + input_value = ConstrainedValue::Mutable(Box::new(input_value)) + } - (keyword.to_string(), value) - } - FunctionInput::MutSelfKeyword(keyword) => { - let value = - self.enforce_function_input(cs, scope, caller_scope, &function_name, None, input_expression)?; - - (keyword.to_string(), value) - } - FunctionInput::Variable(input_model) => { - // First evaluate input expression - let mut input_value = self.enforce_function_input( - cs, - scope, - caller_scope, - &function_name, - Some(input_model.type_.clone()), - input_expression, - )?; - - if input_model.mutable { - input_value = ConstrainedValue::Mutable(Box::new(input_value)) - } - - (input_model.identifier.name.clone(), input_value) - } - }; - - // Store input as variable with {function_name}_{input_name} - let input_program_identifier = new_scope(&function_name, &name); - self.store(input_program_identifier, value); + self.store(variable.id, input_value); } // Evaluate every statement in the function and save all potential results let mut results = vec![]; let indicator = Boolean::constant(true); - for statement in function.block.statements.iter() { - let mut result = self.enforce_statement( - cs, - scope, - &function_name, - &indicator, - statement.clone(), - function.output.clone(), - declared_circuit_reference, - mut_self, - )?; + let output = function.function.output.clone().strong(); - results.append(&mut result); + let mut result = self.enforce_statement(cs, &indicator, &function.body)?; + + results.append(&mut result); + + if function.function.qualifier == FunctionQualifier::MutSelfRef { + if let (Some(self_var), Some(target)) = (self_var, target) { + let new_self = self + .get(&self_var.borrow().id) + .expect("no self variable found in mut self context") + .clone(); + if let Some(assignable_target) = self.resolve_mut_ref(cs, target)? { + if assignable_target.len() != 1 { + panic!("found tuple as a self assignment target"); + } + let assignable_target = assignable_target.into_iter().next().unwrap(); + *assignable_target = new_self; + } else { + // todo: we should report a warning for calling a mutable function on an effectively copied self (i.e. wasn't assignable `tempStruct {x: 5}.myMutSelfFunction()`) + } + } } // Conditionally select a result based on returned indicators - Self::conditionally_select_result(cs, function.output, results, &function.span) + 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 6bedb7575f..1732f87c21 100644 --- a/compiler/src/function/input/array.rs +++ b/compiler/src/function/input/array.rs @@ -16,18 +16,11 @@ //! Allocates an array as a main function input parameter in a compiled Leo program. -use crate::{ - errors::FunctionError, - inner_array_type, - parse_index, - program::{new_scope, ConstrainedProgram}, - value::ConstrainedValue, - GroupType, -}; +use crate::{errors::FunctionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType}; -use leo_ast::{ArrayDimensions, InputValue, Span, Type}; +use leo_asg::Type; +use leo_ast::{InputValue, Span}; -use crate::errors::ExpressionError; use snarkvm_models::{ curves::{Field, PrimeField}, gadgets::r1cs::ConstraintSystem, @@ -38,27 +31,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![]; @@ -66,11 +43,11 @@ impl> ConstrainedProgram { Some(InputValue::Array(arr)) => { // Allocate each value in the current row for (i, value) in arr.into_iter().enumerate() { - let value_name = new_scope(&name, &i.to_string()); + let value_name = format!("{}_{}", &name, &i.to_string()); array_value.push(self.allocate_main_function_input( cs, - inner_array_type.clone(), + array_type, &value_name, Some(value), span, @@ -79,16 +56,10 @@ impl> ConstrainedProgram { } None => { // Allocate all row values as none - for i in 0..expected_length { - let value_name = new_scope(&name, &i.to_string()); + for i in 0..array_len { + let value_name = format!("{}_{}", &name, &i.to_string()); - array_value.push(self.allocate_main_function_input( - cs, - inner_array_type.clone(), - &value_name, - None, - span, - )?); + array_value.push(self.allocate_main_function_input(cs, array_type, &value_name, None, span)?); } } _ => { diff --git a/compiler/src/function/input/function_input.rs b/compiler/src/function/input/function_input.rs deleted file mode 100644 index 190a079c92..0000000000 --- a/compiler/src/function/input/function_input.rs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (C) 2019-2021 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 . - -//! Enforces a function input parameter in a compiled Leo program. - -use crate::{errors::FunctionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType}; - -use leo_ast::{Expression, Type}; - -use snarkvm_models::{ - curves::{Field, PrimeField}, - gadgets::r1cs::ConstraintSystem, -}; - -impl> ConstrainedProgram { - pub fn enforce_function_input>( - &mut self, - cs: &mut CS, - scope: &str, - caller_scope: &str, - function_name: &str, - expected_type: Option, - input: Expression, - ) -> 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)?), - } - } -} diff --git a/compiler/src/function/input/input_keyword.rs b/compiler/src/function/input/input_keyword.rs index bc8acb10de..37f32d9cf1 100644 --- a/compiler/src/function/input/input_keyword.rs +++ b/compiler/src/function/input/input_keyword.rs @@ -15,7 +15,9 @@ // along with the Leo library. If not, see . use crate::{errors::FunctionError, ConstrainedCircuitMember, ConstrainedProgram, ConstrainedValue, GroupType}; -use leo_ast::{Identifier, Input, InputKeyword}; +use leo_asg::{CircuitBody, CircuitMemberBody, Type}; +use leo_ast::{Identifier, Input, Span}; +use std::sync::Arc; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -31,26 +33,27 @@ impl> ConstrainedProgram { pub fn allocate_input_keyword>( &mut self, cs: &mut CS, - keyword: InputKeyword, + 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: keyword.span.clone(), + span: span.clone(), }; let record_name = Identifier { name: RECORD_VARIABLE_NAME.to_string(), - span: keyword.span.clone(), + span: span.clone(), }; let state_name = Identifier { name: STATE_VARIABLE_NAME.to_string(), - span: keyword.span.clone(), + span: span.clone(), }; let state_leaf_name = Identifier { name: STATE_LEAF_VARIABLE_NAME.to_string(), - span: keyword.span.clone(), + span, }; // Fetch each input variable's definitions @@ -72,8 +75,17 @@ 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 +94,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 6cea5b62c0..fea6f597a0 100644 --- a/compiler/src/function/input/input_section.rs +++ b/compiler/src/function/input/input_section.rs @@ -15,7 +15,9 @@ // along with the Leo library. If not, see . use crate::{errors::FunctionError, ConstrainedCircuitMember, ConstrainedProgram, ConstrainedValue, GroupType}; +use leo_asg::{AsgConvertError, CircuitBody, CircuitMemberBody}; 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,24 @@ 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) { + return Err(AsgConvertError::unexpected_type( + &expected_type.to_string(), + Some(&declared_type.to_string()), + &identifier.span, + ) + .into()); + } 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 +68,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 140d582dc2..11c3f8b536 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_asg::Type; +use leo_ast::{InputValue, Span}; 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/mod.rs b/compiler/src/function/input/mod.rs index 761a8abe54..eb45b640d5 100644 --- a/compiler/src/function/input/mod.rs +++ b/compiler/src/function/input/mod.rs @@ -19,9 +19,6 @@ pub mod array; pub use self::array::*; -pub mod function_input; -pub use self::function_input::*; - pub mod main_function_input; pub use self::main_function_input::*; diff --git a/compiler/src/function/input/tuple.rs b/compiler/src/function/input/tuple.rs index c7148cb138..add3eb9240 100644 --- a/compiler/src/function/input/tuple.rs +++ b/compiler/src/function/input/tuple.rs @@ -16,14 +16,10 @@ //! Allocates an array as a main function input parameter in a compiled Leo program. -use crate::{ - errors::FunctionError, - program::{new_scope, ConstrainedProgram}, - value::ConstrainedValue, - GroupType, -}; +use crate::{errors::FunctionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType}; -use leo_ast::{InputValue, Span, Type}; +use leo_asg::Type; +use leo_ast::{InputValue, Span}; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -35,7 +31,7 @@ impl> ConstrainedProgram { &mut self, cs: &mut CS, name: &str, - types: Vec, + types: &[Type], input_value: Option, span: &Span, ) -> Result, FunctionError> { @@ -44,16 +40,16 @@ 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() { - let value_name = new_scope(name, &i.to_string()); + for (i, (value, type_)) in values.into_iter().zip(types.iter()).enumerate() { + let value_name = format!("{}_{}", &name, &i.to_string()); tuple_values.push(self.allocate_main_function_input(cs, type_, &value_name, Some(value), span)?) } } None => { // Allocate all tuple values as none - for (i, type_) in types.into_iter().enumerate() { - let value_name = new_scope(name, &i.to_string()); + for (i, type_) in types.iter().enumerate() { + let value_name = format!("{}_{}", &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 56254ba236..f1003f8c6c 100644 --- a/compiler/src/function/main_function.rs +++ b/compiler/src/function/main_function.rs @@ -16,14 +16,11 @@ //! Enforces constraints on the main function of a compiled Leo program. -use crate::{ - errors::FunctionError, - program::{new_scope, ConstrainedProgram}, - GroupType, - OutputBytes, -}; +use crate::{errors::FunctionError, program::ConstrainedProgram, GroupType, OutputBytes}; -use leo_ast::{Expression, Function, FunctionInput, Identifier, Input}; +use leo_asg::{Expression, FunctionBody, FunctionQualifier}; +use leo_ast::Input; +use std::sync::Arc; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -34,49 +31,67 @@ impl> ConstrainedProgram { pub fn enforce_main_function>( &mut self, cs: &mut CS, - scope: &str, - function: Function, + function: &Arc, input: &Input, ) -> Result { - let function_name = new_scope(scope, function.get_name()); let registers = input.get_registers(); // Iterate over main function input variables and allocate new values - let mut input_variables = Vec::with_capacity(function.input.len()); - for input_model in function.input.clone().into_iter() { - let (input_id, value) = match input_model { - FunctionInput::InputKeyword(keyword) => { - let input_id = Identifier::new_with_span(&keyword.to_string(), &keyword.span); - let value = self.allocate_input_keyword(cs, keyword, input)?; + if function.function.has_input { + // let input_var = function.scope. + let asg_input = function + .scope + .borrow() + .resolve_input() + .expect("no input variable in scope when function is qualified"); - (input_id, value) - } - FunctionInput::SelfKeyword(_) => unimplemented!("cannot access self keyword in main function"), - FunctionInput::MutSelfKeyword(_) => unimplemented!("cannot access mut self keyword in main function"), - FunctionInput::Variable(input_model) => { - let name = input_model.identifier.name.clone(); - let input_option = input - .get(&name) - .ok_or_else(|| FunctionError::input_not_found(name.clone(), function.span.clone()))?; - let input_value = - self.allocate_main_function_input(cs, input_model.type_, &name, input_option, &function.span)?; + let value = self.allocate_input_keyword( + cs, + function.function.name.borrow().span.clone(), + &asg_input.container_circuit, + input, + )?; - (input_model.identifier, input_value) - } - }; - - // Store input as variable with {function_name}_{identifier_name} - let input_name = new_scope(&function_name, &input_id.to_string()); - - // Store a new variable for every allocated main function input - self.store(input_name, value); - - input_variables.push(Expression::Identifier(input_id)); + self.store(asg_input.container.borrow().id, value); } - let span = function.span.clone(); - let result_value = self.enforce_function(cs, scope, &function_name, function, input_variables, "")?; - let output_bytes = OutputBytes::new_from_constrained_value(registers, result_value, span)?; + match function.function.qualifier { + FunctionQualifier::SelfRef | FunctionQualifier::MutSelfRef => { + unimplemented!("cannot access self variable in main function") + } + FunctionQualifier::Static => (), + } + + let mut arguments = vec![]; + + for input_variable in function.arguments.iter() { + { + let input_variable = input_variable.borrow(); + let name = input_variable.name.name.clone(); + let input_option = input.get(&name).ok_or_else(|| { + FunctionError::input_not_found(name.clone(), function.span.clone().unwrap_or_default()) + })?; + let input_value = self.allocate_main_function_input( + cs, + &input_variable.type_, + &name, + input_option, + &function.span.clone().unwrap_or_default(), + )?; + + // Store a new variable for every allocated main function input + self.store(input_variable.id, input_value); + } + arguments.push(Arc::new(Expression::VariableRef(leo_asg::VariableRef { + parent: std::cell::RefCell::new(None), + span: Some(input_variable.borrow().name.span.clone()), + variable: input_variable.clone(), + }))); + } + + let span = function.span.clone().unwrap_or_default(); + let result_value = self.enforce_function(cs, function, None, &arguments)?; + let output_bytes = OutputBytes::new_from_constrained_value(&self.asg, registers, result_value, span)?; Ok(output_bytes) } diff --git a/compiler/src/function/mod.rs b/compiler/src/function/mod.rs index 8a9971313e..2095ebdbf7 100644 --- a/compiler/src/function/mod.rs +++ b/compiler/src/function/mod.rs @@ -27,3 +27,6 @@ pub use self::main_function::*; pub mod result; pub use self::result::*; + +pub mod mut_target; +pub use self::mut_target::*; diff --git a/compiler/src/function/mut_target.rs b/compiler/src/function/mut_target.rs new file mode 100644 index 0000000000..6134c173bc --- /dev/null +++ b/compiler/src/function/mut_target.rs @@ -0,0 +1,124 @@ +// Copyright (C) 2019-2021 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 . + +//! Resolves assignees in a compiled Leo program. + +use crate::{ + errors::StatementError, + program::ConstrainedProgram, + value::ConstrainedValue, + GroupType, + ResolvedAssigneeAccess, +}; +use leo_asg::{ + ArrayAccessExpression, + ArrayRangeAccessExpression, + CircuitAccessExpression, + Expression, + Node, + Span, + TupleAccessExpression, + Variable, +}; +use std::sync::Arc; + +use snarkvm_models::{ + curves::{Field, PrimeField}, + gadgets::r1cs::ConstraintSystem, +}; + +impl> ConstrainedProgram { + fn prepare_mut_access>( + &mut self, + cs: &mut CS, + expr: &Arc, + span: &Span, + output: &mut Vec, + ) -> Result, StatementError> { + match &**expr { + Expression::ArrayRangeAccess(ArrayRangeAccessExpression { array, left, right, .. }) => { + let inner = self.prepare_mut_access(cs, array, span, output)?; + let start_index = left + .as_ref() + .map(|start| self.enforce_index(cs, start, &span)) + .transpose()?; + let stop_index = right + .as_ref() + .map(|stop| self.enforce_index(cs, stop, &span)) + .transpose()?; + + output.push(ResolvedAssigneeAccess::ArrayRange(start_index, stop_index)); + Ok(inner) + } + Expression::ArrayAccess(ArrayAccessExpression { array, index, .. }) => { + let inner = self.prepare_mut_access(cs, array, span, output)?; + let index = self.enforce_index(cs, index, &span)?; + + output.push(ResolvedAssigneeAccess::ArrayIndex(index)); + Ok(inner) + } + Expression::TupleAccess(TupleAccessExpression { tuple_ref, index, .. }) => { + let inner = self.prepare_mut_access(cs, tuple_ref, span, output)?; + + output.push(ResolvedAssigneeAccess::Tuple(*index, span.clone())); + Ok(inner) + } + Expression::CircuitAccess(CircuitAccessExpression { + target: Some(target), + member, + .. + }) => { + let inner = self.prepare_mut_access(cs, target, span, output)?; + + output.push(ResolvedAssigneeAccess::Member(member.clone())); + Ok(inner) + } + Expression::VariableRef(variable_ref) => Ok(Some(variable_ref.variable.clone())), + _ => Ok(None), // not a valid reference to mutable variable, we copy + } + } + + // resolve a mutable reference from an expression + // return Ok(None) if no valid mutable reference, or Err(_) on more critical error + pub fn resolve_mut_ref>( + &mut self, + cs: &mut CS, + assignee: &Arc, + ) -> Result>>, StatementError> { + let span = assignee.span().cloned().unwrap_or_default(); + + let mut accesses = vec![]; + let target = self.prepare_mut_access(cs, assignee, &span, &mut accesses)?; + if target.is_none() { + return Ok(None); + } + let variable = target.unwrap(); + let variable = variable.borrow(); + + let mut result = vec![match self.get_mut(&variable.id) { + Some(value) => match value { + ConstrainedValue::Mutable(mutable) => &mut **mutable, + _ => return Err(StatementError::immutable_assign(variable.name.to_string(), span)), + }, + None => return Err(StatementError::undefined_variable(variable.name.to_string(), span)), + }]; + + for access in accesses { + result = Self::resolve_assignee_access(access, &span, result)?; + } + Ok(Some(result)) + } +} diff --git a/compiler/src/function/result/result.rs b/compiler/src/function/result/result.rs index a82b19d555..7744c6e2ec 100644 --- a/compiler/src/function/result/result.rs +++ b/compiler/src/function/result/result.rs @@ -17,7 +17,6 @@ //! Enforces that one return value is produced in a compiled Leo program. use crate::{ - check_return_type, errors::StatementError, get_indicator_value, program::ConstrainedProgram, @@ -25,7 +24,7 @@ use crate::{ GroupType, }; -use leo_ast::{Span, Type}; +use leo_asg::{Span, Type}; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -42,37 +41,21 @@ impl> ConstrainedProgram { /// pub fn conditionally_select_result>( cs: &mut CS, - expected_return: Option, + expected_return: &Type, results: Vec<(Boolean, ConstrainedValue)>, span: &Span, ) -> Result, StatementError> { // Initialize empty return value. let mut return_value = ConstrainedValue::Tuple(vec![]); - // If the function does not expect a return type, then make sure there are no returned results. - let return_type = match expected_return { - Some(return_type) => return_type, - None => { - if results.is_empty() { - // If the function has no returns, then return an empty tuple. - return Ok(return_value); - } else { - return Err(StatementError::invalid_number_of_returns( - 0, - results.len(), - span.to_owned(), - )); - } - } - }; - // Error if the function or one of its branches does not return. - if results - .iter() - .find(|(indicator, _res)| get_indicator_value(indicator)) - .is_none() + if !expected_return.is_unit() + && results + .iter() + .find(|(indicator, _res)| get_indicator_value(indicator)) + .is_none() { - return Err(StatementError::no_returns(return_type, span.to_owned())); + return Err(StatementError::no_returns(&expected_return, span.to_owned())); } // Find the return value @@ -81,7 +64,13 @@ impl> ConstrainedProgram { for (indicator, result) in results.into_iter() { // Error if a statement returned a result with an incorrect type let result_type = result.to_type(span)?; - check_return_type(&return_type, &result_type, span)?; + if !expected_return.is_assignable_from(&result_type) { + panic!( + "failed type resolution for function return: expected '{}', got '{}'", + expected_return.to_string(), + result_type.to_string() + ); + } if get_indicator_value(&indicator) { // Error if we already have a return value. diff --git a/compiler/src/import/mod.rs b/compiler/src/import/mod.rs deleted file mode 100644 index b50745b166..0000000000 --- a/compiler/src/import/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (C) 2019-2021 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/import.rs b/compiler/src/import/store/import.rs deleted file mode 100644 index 40ba8e607f..0000000000 --- a/compiler/src/import/store/import.rs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (C) 2019-2021 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()))?; - - // Parse imported program - self.store_definitions(program, imported_programs)?; - - // 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 6eddd9523f..0000000000 --- a/compiler/src/import/store/mod.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (C) 2019-2021 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 d1bc151025..0000000000 --- a/compiler/src/import/store/symbol.rs +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (C) 2019-2021 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 c94a638aae..626733ba3d 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::*; @@ -53,5 +50,11 @@ pub use self::program::*; pub mod statement; pub use self::statement::*; +pub mod prelude; +pub use self::prelude::*; + pub mod value; pub use self::value::*; + +pub mod stage; +pub use self::stage::*; diff --git a/compiler/src/output/output_bytes.rs b/compiler/src/output/output_bytes.rs index f69dcfe80f..c050c71749 100644 --- a/compiler/src/output/output_bytes.rs +++ b/compiler/src/output/output_bytes.rs @@ -15,6 +15,7 @@ // along with the Leo library. If not, see . use crate::{errors::OutputBytesError, ConstrainedValue, GroupType, REGISTERS_VARIABLE_NAME}; +use leo_asg::Program; use leo_ast::{Parameter, Registers, Span}; use snarkvm_models::curves::{Field, PrimeField}; @@ -31,6 +32,7 @@ impl OutputBytes { } pub fn new_from_constrained_value>( + program: &Program, registers: &Registers, value: ConstrainedValue, span: Span, @@ -65,13 +67,13 @@ impl OutputBytes { let name = parameter.variable.name; // Check register type == return value type. - let register_type = parameter.type_; + let register_type = program.borrow().scope.borrow().resolve_ast_type(¶meter.type_)?; let return_value_type = value.to_type(&span)?; - if !register_type.eq_flat(&return_value_type) { + if !register_type.is_assignable_from(&return_value_type) { return Err(OutputBytesError::mismatched_output_types( - register_type, - return_value_type, + ®ister_type, + &return_value_type, span, )); } diff --git a/compiler/src/prelude/blake2s.rs b/compiler/src/prelude/blake2s.rs new file mode 100644 index 0000000000..7fb25ba495 --- /dev/null +++ b/compiler/src/prelude/blake2s.rs @@ -0,0 +1,82 @@ +// Copyright (C) 2019-2021 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 std::sync::Arc; + +use super::CoreCircuit; +use crate::{errors::ExpressionError, ConstrainedValue, GroupType, Integer}; +use leo_asg::{FunctionBody, Span}; +use snarkvm_gadgets::algorithms::prf::Blake2sGadget; +use snarkvm_models::{ + curves::{Field, PrimeField}, + gadgets::{ + algorithms::PRFGadget, + r1cs::ConstraintSystem, + utilities::{uint::UInt8, ToBytesGadget}, + }, +}; + +pub struct Blake2s; + +fn unwrap_argument>(mut arg: ConstrainedValue) -> Vec { + arg.get_inner_mut(); + if let ConstrainedValue::Array(args) = arg { + assert_eq!(args.len(), 32); // asg enforced + args.into_iter() + .map(|item| { + if let ConstrainedValue::Integer(Integer::U8(item)) = item { + item + } else { + panic!("illegal non-u8 type in blake2s call"); + } + }) + .collect() + } else { + panic!("illegal non-array type in blake2s call"); + } +} + +impl> CoreCircuit for Blake2s { + fn call_function>( + &self, + cs: &mut CS, + function: Arc, + span: &Span, + target: Option>, + mut arguments: Vec>, + ) -> Result, ExpressionError> { + assert_eq!(arguments.len(), 2); // asg enforced + assert!(function.function.name.borrow().name == "hash"); // asg enforced + assert!(target.is_none()); // asg enforced + let input = unwrap_argument(arguments.remove(1)); + let seed = unwrap_argument(arguments.remove(0)); + + let digest = + Blake2sGadget::check_evaluation_gadget(cs.ns(|| "blake2s hash"), &seed[..], &input[..]).map_err(|e| { + ExpressionError::cannot_enforce("Blake2s check evaluation gadget".to_owned(), e, span.clone()) + })?; + + Ok(ConstrainedValue::Array( + digest + .to_bytes(cs) + .map_err(|e| ExpressionError::cannot_enforce("Vec ToBytes".to_owned(), e, span.clone()))? + .into_iter() + .map(Integer::U8) + .map(ConstrainedValue::Integer) + .collect(), + )) + } +} diff --git a/core/src/types/core_circuit.rs b/compiler/src/prelude/mod.rs similarity index 51% rename from core/src/types/core_circuit.rs rename to compiler/src/prelude/mod.rs index 430b7bb6b0..1c924668f8 100644 --- a/core/src/types/core_circuit.rs +++ b/compiler/src/prelude/mod.rs @@ -14,28 +14,32 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::{CoreCircuitError, Value}; -use leo_ast::{Circuit, Identifier, Span}; +pub mod blake2s; +use std::sync::Arc; +pub use blake2s::*; + +use crate::{errors::ExpressionError, ConstrainedValue, GroupType}; +use leo_asg::{FunctionBody, Span}; use snarkvm_models::{ curves::{Field, PrimeField}, gadgets::r1cs::ConstraintSystem, }; -/// A core circuit type, accessible to all Leo programs by default. -/// To access a `CoreCircuit`, import its symbol from a `CorePackage`. -pub trait CoreCircuit { - /// The name of the core circuit function - fn name() -> String; - - /// Return the abstract syntax tree representation of the core circuit for compiler parsing. - fn ast(circuit_name: Identifier, span: Span) -> Circuit; - - /// Call the gadget associated with this core circuit with arguments. - /// Generate constraints on the given `ConstraintSystem`. - fn call>( - cs: CS, - arguments: Vec, - span: Span, - ) -> Result, CoreCircuitError>; +pub trait CoreCircuit>: Send + Sync { + fn call_function>( + &self, + cs: &mut CS, + function: Arc, + span: &Span, + target: Option>, + arguments: Vec>, + ) -> Result, ExpressionError>; +} + +pub fn resolve_core_circuit>(name: &str) -> impl CoreCircuit { + match name { + "blake2s" => Blake2s, + _ => unimplemented!("invalid core circuit: {}", name), + } } diff --git a/compiler/src/program/program.rs b/compiler/src/program/program.rs index f2f15267a0..bdcbd0d44d 100644 --- a/compiler/src/program/program.rs +++ b/compiler/src/program/program.rs @@ -18,44 +18,34 @@ use crate::{value::ConstrainedValue, GroupType}; +use leo_asg::Program; use snarkvm_models::curves::{Field, PrimeField}; use indexmap::IndexMap; +use uuid::Uuid; pub struct ConstrainedProgram> { - pub identifiers: IndexMap>, -} - -impl> Default for ConstrainedProgram { - fn default() -> Self { - Self { - identifiers: IndexMap::new(), - } - } -} - -pub fn new_scope(outer: &str, inner: &str) -> String { - format!("{}_{}", outer, inner) -} - -pub fn is_in_scope(current_scope: &str, desired_scope: &str) -> bool { - current_scope.ends_with(desired_scope) + pub asg: Program, + identifiers: IndexMap>, } impl> ConstrainedProgram { - pub fn new() -> Self { - Self::default() + pub fn new(asg: Program) -> Self { + Self { + asg, + identifiers: IndexMap::new(), + } } - pub(crate) fn store(&mut self, name: String, value: ConstrainedValue) { + pub(crate) fn store(&mut self, name: Uuid, value: ConstrainedValue) { self.identifiers.insert(name, value); } - pub(crate) fn get(&self, name: &str) -> Option<&ConstrainedValue> { + pub(crate) fn get(&self, name: &Uuid) -> Option<&ConstrainedValue> { self.identifiers.get(name) } - pub(crate) fn get_mut(&mut self, name: &str) -> Option<&mut ConstrainedValue> { + pub(crate) fn get_mut(&mut self, name: &Uuid) -> Option<&mut ConstrainedValue> { self.identifiers.get_mut(name) } } diff --git a/core/src/packages/unstable/mod.rs b/compiler/src/stage.rs similarity index 90% rename from core/src/packages/unstable/mod.rs rename to compiler/src/stage.rs index fd4c347b1e..ec96dac0fd 100644 --- a/core/src/packages/unstable/mod.rs +++ b/compiler/src/stage.rs @@ -14,5 +14,8 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -pub mod blake2s; -pub use self::blake2s::*; +use leo_asg::Program; + +pub trait ASGStage { + fn apply(asg: &mut Program); +} diff --git a/compiler/src/statement/assign/assign.rs b/compiler/src/statement/assign/assign.rs index 66beadfa54..24a0957df5 100644 --- a/compiler/src/statement/assign/assign.rs +++ b/compiler/src/statement/assign/assign.rs @@ -16,15 +16,8 @@ //! Enforces an assign statement in a compiled Leo program. -use crate::{ - arithmetic::*, - errors::StatementError, - new_scope, - program::ConstrainedProgram, - value::ConstrainedValue, - GroupType, -}; -use leo_ast::{AssignOperation, AssignStatement, AssigneeAccess, Span}; +use crate::{arithmetic::*, errors::StatementError, program::ConstrainedProgram, value::ConstrainedValue, GroupType}; +use leo_asg::{AssignOperation, AssignStatement, Span}; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -39,28 +32,15 @@ impl> ConstrainedProgram { pub fn enforce_assign_statement>( &mut self, cs: &mut CS, - file_scope: &str, - function_scope: &str, - declared_circuit_reference: &str, indicator: &Boolean, - mut_self: bool, - statement: AssignStatement, + statement: &AssignStatement, ) -> Result<(), StatementError> { // Get the name of the variable we are assigning to - let mut new_value = self.enforce_expression(cs, file_scope, function_scope, None, statement.value)?; - let mut resolved_assignee = self.resolve_assignee( - cs, - file_scope, - function_scope, - declared_circuit_reference, - mut_self, - statement.assignee.clone(), - )?; + let new_value = self.enforce_expression(cs, &statement.value)?; + let mut resolved_assignee = self.resolve_assign(cs, statement)?; if resolved_assignee.len() == 1 { - new_value.resolve_type(Some(resolved_assignee[0].to_type(&statement.span)?), &statement.span)?; - - let span = statement.span.clone(); + let span = statement.span.clone().unwrap_or_default(); Self::enforce_assign_operation( cs, @@ -74,7 +54,7 @@ impl> ConstrainedProgram { } else { match new_value { ConstrainedValue::Array(new_values) => { - let span = statement.span.clone(); + let span = statement.span.clone().unwrap_or_default(); for (i, (old_ref, new_value)) in resolved_assignee.into_iter().zip(new_values.into_iter()).enumerate() @@ -90,35 +70,12 @@ impl> ConstrainedProgram { )?; } } - _ => return Err(StatementError::array_assign_range(statement.span)), - }; - } - - // self re-store logic -- structure is already checked by enforce_assign_operation - if statement.assignee.identifier.is_self() && mut_self { - if let Some(AssigneeAccess::Member(member_name)) = statement.assignee.accesses.get(0) { - let self_circuit_variable_name = new_scope(&statement.assignee.identifier.name, &member_name.name); - let self_variable_name = new_scope(file_scope, &self_circuit_variable_name); - // get circuit ref - let target = match self.get(declared_circuit_reference) { - Some(ConstrainedValue::Mutable(value)) => &**value, - _ => unimplemented!(), - }; - // get freshly assigned member ref, and clone it - let source = match target { - ConstrainedValue::CircuitExpression(_circuit_name, members) => { - let matched_variable = members.iter().find(|member| &member.0 == member_name); - - match matched_variable { - Some(member) => &member.1, - None => unimplemented!(), - } - } - _ => unimplemented!(), + _ => { + return Err(StatementError::array_assign_range( + statement.span.clone().unwrap_or_default(), + )); } - .clone(); - self.store(self_variable_name, source); - } + }; } Ok(()) @@ -130,11 +87,9 @@ impl> ConstrainedProgram { scope: String, operation: &AssignOperation, target: &mut ConstrainedValue, - mut new_value: ConstrainedValue, + new_value: ConstrainedValue, span: &Span, ) -> Result<(), StatementError> { - new_value.resolve_type(Some(target.to_type(span)?), span)?; - let new_value = match operation { AssignOperation::Assign => new_value, AssignOperation::Add => enforce_add(cs, target.clone(), new_value, span)?, diff --git a/compiler/src/statement/assign/assignee.rs b/compiler/src/statement/assign/assignee.rs index 8d7c1bcff1..2b50f3cb80 100644 --- a/compiler/src/statement/assign/assignee.rs +++ b/compiler/src/statement/assign/assignee.rs @@ -16,79 +16,62 @@ //! Resolves assignees in a compiled Leo program. -use crate::{ - errors::StatementError, - new_scope, - parse_index, - program::ConstrainedProgram, - value::ConstrainedValue, - GroupType, -}; -use leo_ast::{Assignee, AssigneeAccess, Identifier, PositiveNumber, Span}; +use crate::{errors::StatementError, program::ConstrainedProgram, value::ConstrainedValue, GroupType}; +use leo_asg::{AssignAccess, AssignStatement, Identifier, Span}; use snarkvm_models::{ curves::{Field, PrimeField}, gadgets::r1cs::ConstraintSystem, }; -enum ResolvedAssigneeAccess { +pub(crate) enum ResolvedAssigneeAccess { ArrayRange(Option, Option), ArrayIndex(usize), - Tuple(PositiveNumber, Span), + Tuple(usize, Span), Member(Identifier), } impl> ConstrainedProgram { - pub fn resolve_assignee>( + pub fn resolve_assign>( &mut self, cs: &mut CS, - file_scope: &str, - function_scope: &str, - declared_circuit_reference: &str, - mut_self: bool, - assignee: Assignee, + assignee: &AssignStatement, ) -> Result>, StatementError> { - let value_ref = if assignee.identifier.is_self() { - if !mut_self { - return Err(StatementError::immutable_assign("self".to_string(), assignee.span)); - } - declared_circuit_reference.to_string() - } else { - new_scope(&function_scope, &assignee.identifier().to_string()) - }; - - let span = assignee.span.clone(); - let identifier_string = assignee.identifier.to_string(); + let span = assignee.span.clone().unwrap_or_default(); let resolved_accesses = assignee - .accesses - .into_iter() + .target_accesses + .iter() .map(|access| match access { - AssigneeAccess::ArrayRange(start, stop) => { + AssignAccess::ArrayRange(start, stop) => { let start_index = start - .map(|start| self.enforce_index(cs, file_scope, function_scope, start, &span)) + .as_ref() + .map(|start| self.enforce_index(cs, start, &span)) .transpose()?; let stop_index = stop - .map(|stop| self.enforce_index(cs, file_scope, function_scope, stop, &span)) + .as_ref() + .map(|stop| self.enforce_index(cs, stop, &span)) .transpose()?; Ok(ResolvedAssigneeAccess::ArrayRange(start_index, stop_index)) } - AssigneeAccess::ArrayIndex(index) => { - let index = self.enforce_index(cs, file_scope, function_scope, index, &span)?; + AssignAccess::ArrayIndex(index) => { + let index = self.enforce_index(cs, index, &span)?; Ok(ResolvedAssigneeAccess::ArrayIndex(index)) } - AssigneeAccess::Tuple(index, span) => Ok(ResolvedAssigneeAccess::Tuple(index, span)), - AssigneeAccess::Member(identifier) => Ok(ResolvedAssigneeAccess::Member(identifier)), + AssignAccess::Tuple(index) => Ok(ResolvedAssigneeAccess::Tuple(*index, span.clone())), + AssignAccess::Member(identifier) => Ok(ResolvedAssigneeAccess::Member(identifier.clone())), }) .collect::, crate::errors::ExpressionError>>()?; - let mut result = vec![match self.get_mut(&value_ref) { + let variable = assignee.target_variable.borrow(); + + let mut result = vec![match self.get_mut(&variable.id) { Some(value) => match value { ConstrainedValue::Mutable(mutable) => &mut **mutable, - _ => return Err(StatementError::immutable_assign(identifier_string, span)), + _ => return Err(StatementError::immutable_assign(variable.name.to_string(), span)), }, - None => return Err(StatementError::undefined_variable(identifier_string, span)), + None => return Err(StatementError::undefined_variable(variable.name.to_string(), span)), }]; for access in resolved_accesses { @@ -121,12 +104,13 @@ impl> ConstrainedProgram { // discards unnecessary mutable wrappers fn unwrap_mutable(input: &mut ConstrainedValue) -> &mut ConstrainedValue { match input { - ConstrainedValue::Mutable(x) => &mut **x, + ConstrainedValue::Mutable(x) => Self::unwrap_mutable(&mut **x), x => x, } } - fn resolve_assignee_access<'a>( + // todo: this can prob have most of its error checking removed + pub(crate) fn resolve_assignee_access<'a>( access: ResolvedAssigneeAccess, span: &Span, mut value: Vec<&'a mut ConstrainedValue>, @@ -174,8 +158,6 @@ impl> ConstrainedProgram { } } ResolvedAssigneeAccess::Tuple(index, span) => { - let index = parse_index(&index, &span)?; - if value.len() != 1 { return Err(StatementError::array_assign_interior_index(span)); } @@ -200,23 +182,7 @@ impl> ConstrainedProgram { let matched_variable = members.iter_mut().find(|member| member.0 == name); match matched_variable { - Some(member) => match &mut member.1 { - ConstrainedValue::Function(_circuit_identifier, function) => { - // Throw an error if we try to mutate a circuit function - Err(StatementError::immutable_circuit_function( - function.identifier.to_string(), - span.to_owned(), - )) - } - ConstrainedValue::Static(_circuit_function) => { - // Throw an error if we try to mutate a static circuit function - Err(StatementError::immutable_circuit_function( - "static".into(), - span.to_owned(), - )) - } - value => Ok(vec![value]), - }, + Some(member) => Ok(vec![&mut member.1]), None => { // Throw an error if the circuit variable does not exist in the circuit Err(StatementError::undefined_circuit_variable( @@ -227,30 +193,9 @@ impl> ConstrainedProgram { } } // Throw an error if the circuit definition does not exist in the file - _ => Err(StatementError::undefined_circuit(name.to_string(), span.to_owned())), + x => Err(StatementError::undefined_circuit(x.to_string(), span.to_owned())), } } } } - - pub fn get_mutable_assignee( - &mut self, - name: &str, - span: &Span, - ) -> Result<&mut ConstrainedValue, StatementError> { - // Check that assignee exists and is mutable - Ok(match self.get_mut(name) { - Some(value) => match value { - ConstrainedValue::Mutable(mutable_value) => { - // Get the mutable value. - mutable_value.get_inner_mut(); - - // Return the mutable value. - mutable_value - } - _ => return Err(StatementError::immutable_assign(name.to_owned(), span.to_owned())), - }, - None => return Err(StatementError::undefined_variable(name.to_owned(), span.to_owned())), - }) - } } diff --git a/compiler/src/statement/assign/mod.rs b/compiler/src/statement/assign/mod.rs index 7691435c86..08fc4f2311 100644 --- a/compiler/src/statement/assign/mod.rs +++ b/compiler/src/statement/assign/mod.rs @@ -20,4 +20,4 @@ pub mod assign; pub use self::assign::*; pub mod assignee; -pub use self::assignee::*; +pub(crate) use self::assignee::*; diff --git a/compiler/src/statement/block/block.rs b/compiler/src/statement/block/block.rs index 68edf5aab6..44b3bb53e0 100644 --- a/compiler/src/statement/block/block.rs +++ b/compiler/src/statement/block/block.rs @@ -17,7 +17,7 @@ //! Enforces a branch of a conditional or iteration statement in a compiled Leo program. use crate::{program::ConstrainedProgram, GroupType, IndicatorAndConstrainedValue, StatementResult}; -use leo_ast::{Block, Type}; +use leo_asg::BlockStatement; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -31,27 +31,13 @@ impl> ConstrainedProgram { pub fn evaluate_block>( &mut self, cs: &mut CS, - file_scope: &str, - function_scope: &str, indicator: &Boolean, - block: Block, - return_type: Option, - declared_circuit_reference: &str, - mut_self: bool, + block: &BlockStatement, ) -> StatementResult>> { let mut results = Vec::with_capacity(block.statements.len()); // Evaluate statements. Only allow a single return argument to be returned. - for statement in block.statements.into_iter() { - let value = self.enforce_statement( - cs, - file_scope, - function_scope, - indicator, - statement, - return_type.clone(), - declared_circuit_reference, - mut_self, - )?; + for statement in block.statements.iter() { + let value = self.enforce_statement(cs, indicator, statement)?; results.extend(value); } diff --git a/compiler/src/statement/conditional/conditional.rs b/compiler/src/statement/conditional/conditional.rs index 58d546ab5c..37e1e9693d 100644 --- a/compiler/src/statement/conditional/conditional.rs +++ b/compiler/src/statement/conditional/conditional.rs @@ -24,7 +24,7 @@ use crate::{ IndicatorAndConstrainedValue, StatementResult, }; -use leo_ast::{ConditionalStatement, Type}; +use leo_asg::ConditionalStatement; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -47,33 +47,18 @@ impl> ConstrainedProgram { pub fn enforce_conditional_statement>( &mut self, cs: &mut CS, - file_scope: &str, - function_scope: &str, indicator: &Boolean, - return_type: Option, - declared_circuit_reference: &str, - mut_self: bool, - statement: ConditionalStatement, + statement: &ConditionalStatement, ) -> StatementResult>> { - let statement_string = statement.to_string(); - + let span = statement.span.clone().unwrap_or_default(); // Inherit an indicator from a previous statement. let outer_indicator = indicator; // Evaluate the conditional boolean as the inner indicator - let inner_indicator = match self.enforce_expression( - cs, - file_scope, - function_scope, - Some(Type::Boolean), - statement.condition.clone(), - )? { + let inner_indicator = match self.enforce_expression(cs, &statement.condition)? { ConstrainedValue::Boolean(resolved) => resolved, value => { - return Err(StatementError::conditional_boolean( - value.to_string(), - statement.span.clone(), - )); + return Err(StatementError::conditional_boolean(value.to_string(), span)); } }; @@ -85,30 +70,16 @@ impl> ConstrainedProgram { outer_indicator_string, inner_indicator_string ); let branch_1_indicator = Boolean::and( - &mut cs.ns(|| { - format!( - "branch 1 {} {}:{}", - statement_string, &statement.span.line, &statement.span.start - ) - }), + &mut cs.ns(|| format!("branch 1 {} {}:{}", span.text, &span.line, &span.start)), outer_indicator, &inner_indicator, ) - .map_err(|_| StatementError::indicator_calculation(branch_1_name, statement.span.clone()))?; + .map_err(|_| StatementError::indicator_calculation(branch_1_name, span.clone()))?; let mut results = vec![]; // Evaluate branch 1 - let mut branch_1_result = self.evaluate_block( - cs, - file_scope, - function_scope, - &branch_1_indicator, - statement.block, - return_type.clone(), - declared_circuit_reference, - mut_self, - )?; + let mut branch_1_result = self.enforce_statement(cs, &branch_1_indicator, &statement.result)?; results.append(&mut branch_1_result); @@ -119,26 +90,16 @@ impl> ConstrainedProgram { "branch indicator 2 {} && {}", outer_indicator_string, inner_indicator_string ); - let span = statement.span.clone(); let branch_2_indicator = Boolean::and( - &mut cs.ns(|| format!("branch 2 {} {}:{}", statement_string, &span.line, &span.start)), + &mut cs.ns(|| format!("branch 2 {} {}:{}", span.text, &span.line, &span.start)), &outer_indicator, &inner_indicator, ) .map_err(|_| StatementError::indicator_calculation(branch_2_name, span.clone()))?; // Evaluate branch 2 - let mut branch_2_result = match statement.next { - Some(next) => self.enforce_statement( - cs, - file_scope, - function_scope, - &branch_2_indicator, - *next, - return_type, - declared_circuit_reference, - mut_self, - )?, + let mut branch_2_result = match &statement.next { + Some(next) => self.enforce_statement(cs, &branch_2_indicator, next)?, None => vec![], }; diff --git a/compiler/src/statement/definition/definition.rs b/compiler/src/statement/definition/definition.rs index e93d715b3b..df04d9ed6b 100644 --- a/compiler/src/statement/definition/definition.rs +++ b/compiler/src/statement/definition/definition.rs @@ -17,7 +17,7 @@ //! Enforces a definition statement in a compiled Leo program. use crate::{errors::StatementError, program::ConstrainedProgram, ConstrainedValue, GroupType}; -use leo_ast::{Declare, DefinitionStatement, Span, VariableName}; +use leo_asg::{DefinitionStatement, Span, Variable}; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -25,35 +25,9 @@ use snarkvm_models::{ }; impl> ConstrainedProgram { - fn enforce_single_definition>( + fn enforce_multiple_definition( &mut self, - cs: &mut CS, - function_scope: &str, - is_constant: bool, - variable_name: VariableName, - mut value: ConstrainedValue, - span: &Span, - ) -> Result<(), StatementError> { - if is_constant && variable_name.mutable { - return Err(StatementError::immutable_assign( - variable_name.to_string(), - span.to_owned(), - )); - } else { - value.allocate_value(cs, span)? - } - - self.store_definition(function_scope, variable_name.mutable, variable_name.identifier, value); - - Ok(()) - } - - fn enforce_multiple_definition>( - &mut self, - cs: &mut CS, - function_scope: &str, - is_constant: bool, - variable_names: Vec, + variable_names: &[Variable], values: Vec>, span: &Span, ) -> Result<(), StatementError> { @@ -65,8 +39,8 @@ impl> ConstrainedProgram { )); } - for (variable, value) in variable_names.into_iter().zip(values.into_iter()) { - self.enforce_single_definition(cs, function_scope, is_constant, variable, value, span)?; + for (variable, value) in variable_names.iter().zip(values.into_iter()) { + self.store_definition(variable, value); } Ok(()) @@ -76,39 +50,25 @@ impl> ConstrainedProgram { pub fn enforce_definition_statement>( &mut self, cs: &mut CS, - file_scope: &str, - function_scope: &str, - statement: DefinitionStatement, + statement: &DefinitionStatement, ) -> Result<(), StatementError> { - let num_variables = statement.variable_names.len(); - let is_constant = match statement.declaration_type { - Declare::Let => false, - Declare::Const => true, - }; - let expression = - self.enforce_expression(cs, file_scope, function_scope, statement.type_.clone(), statement.value)?; + let num_variables = statement.variables.len(); + let expression = self.enforce_expression(cs, &statement.value)?; + let span = statement.span.clone().unwrap_or_default(); if num_variables == 1 { // Define a single variable with a single value - let variable = statement.variable_names[0].clone(); - - self.enforce_single_definition(cs, function_scope, is_constant, variable, expression, &statement.span) + self.store_definition(statement.variables.get(0).unwrap(), expression); + Ok(()) } else { // Define multiple variables for an expression that returns multiple results (multiple definition) let values = match expression { // ConstrainedValue::Return(values) => values, ConstrainedValue::Tuple(values) => values, - value => return Err(StatementError::multiple_definition(value.to_string(), statement.span)), + value => return Err(StatementError::multiple_definition(value.to_string(), span)), }; - self.enforce_multiple_definition( - cs, - function_scope, - is_constant, - statement.variable_names, - values, - &statement.span, - ) + self.enforce_multiple_definition(&statement.variables, values, &span) } } } diff --git a/compiler/src/statement/iteration/iteration.rs b/compiler/src/statement/iteration/iteration.rs index 8c3bb9e852..1cdaad0952 100644 --- a/compiler/src/statement/iteration/iteration.rs +++ b/compiler/src/statement/iteration/iteration.rs @@ -17,7 +17,6 @@ //! Enforces an iteration statement in a compiled Leo program. use crate::{ - new_scope, program::ConstrainedProgram, value::ConstrainedValue, GroupType, @@ -25,7 +24,7 @@ use crate::{ Integer, StatementResult, }; -use leo_ast::{IterationStatement, Type}; +use leo_asg::IterationStatement; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -40,41 +39,32 @@ impl> ConstrainedProgram { pub fn enforce_iteration_statement>( &mut self, cs: &mut CS, - file_scope: &str, - function_scope: &str, indicator: &Boolean, - return_type: Option, - declared_circuit_reference: &str, - mut_self: bool, - statement: IterationStatement, + statement: &IterationStatement, ) -> StatementResult>> { let mut results = vec![]; - let from = self.enforce_index(cs, file_scope, function_scope, statement.start, &statement.span)?; - let to = self.enforce_index(cs, file_scope, function_scope, statement.stop, &statement.span)?; + let span = statement.span.clone().unwrap_or_default(); + + let from = self.enforce_index(cs, &statement.start, &span)?; + let to = self.enforce_index(cs, &statement.stop, &span)?; - let span = statement.span.clone(); for i in from..to { // Store index in current function scope. // For loop scope is not implemented. + let variable = statement.variable.borrow(); - let index_name = new_scope(function_scope, &statement.variable.name); - + // todo: replace definition with var typed self.store( - index_name, + variable.id, ConstrainedValue::Integer(Integer::U32(UInt32::constant(i as u32))), ); // Evaluate statements and possibly return early - let result = self.evaluate_block( + let result = self.enforce_statement( &mut cs.ns(|| format!("for loop iteration {} {}:{}", i, &span.line, &span.start)), - file_scope, - function_scope, indicator, - statement.block.clone(), - return_type.clone(), - declared_circuit_reference, - mut_self, + &statement.body, )?; results.extend(result); diff --git a/compiler/src/statement/return_/return_.rs b/compiler/src/statement/return_/return_.rs index 07b19e3b44..2dd261013a 100644 --- a/compiler/src/statement/return_/return_.rs +++ b/compiler/src/statement/return_/return_.rs @@ -17,49 +17,20 @@ //! Enforces a return statement in a compiled Leo program. use crate::{errors::StatementError, program::ConstrainedProgram, value::ConstrainedValue, GroupType}; -use leo_ast::{ReturnStatement, Span, Type}; +use leo_asg::ReturnStatement; use snarkvm_models::{ curves::{Field, PrimeField}, gadgets::r1cs::ConstraintSystem, }; -/// Returns `Ok` if the expected type == actual type, returns `Err` otherwise. -pub fn check_return_type(expected: &Type, actual: &Type, span: &Span) -> Result<(), StatementError> { - if expected.ne(&actual) { - // If the return type is `SelfType` returning the circuit type is okay. - return if (expected.is_self() && actual.is_circuit()) || expected.eq_flat(&actual) { - Ok(()) - } else { - Err(StatementError::arguments_type(&expected, &actual, span.to_owned())) - }; - } - Ok(()) -} - impl> ConstrainedProgram { pub fn enforce_return_statement>( &mut self, cs: &mut CS, - file_scope: &str, - function_scope: &str, - return_type: Option, - statement: ReturnStatement, + statement: &ReturnStatement, ) -> Result, StatementError> { - let result = self.enforce_operand( - cs, - file_scope, - function_scope, - return_type.clone(), - statement.expression, - &statement.span, - )?; - - // Make sure we return the correct type. - if let Some(expected) = return_type { - check_return_type(&expected, &result.to_type(&statement.span)?, &statement.span)?; - } - + let result = self.enforce_operand(cs, &statement.expression)?; Ok(result) } } diff --git a/compiler/src/statement/statement.rs b/compiler/src/statement/statement.rs index 2e08223f7c..7233d663ab 100644 --- a/compiler/src/statement/statement.rs +++ b/compiler/src/statement/statement.rs @@ -17,7 +17,8 @@ //! Enforces a statement in a compiled Leo program. use crate::{errors::StatementError, program::ConstrainedProgram, value::ConstrainedValue, GroupType}; -use leo_ast::{Statement, Type}; +use leo_asg::Statement; +use std::sync::Arc; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -39,73 +40,38 @@ impl> ConstrainedProgram { pub fn enforce_statement>( &mut self, cs: &mut CS, - file_scope: &str, - function_scope: &str, indicator: &Boolean, - statement: Statement, - return_type: Option, - declared_circuit_reference: &str, - mut_self: bool, + statement: &Arc, ) -> StatementResult>> { let mut results = vec![]; - match statement { + match &**statement { Statement::Return(statement) => { - let return_value = ( - *indicator, - self.enforce_return_statement(cs, file_scope, function_scope, return_type, statement)?, - ); + let return_value = (*indicator, self.enforce_return_statement(cs, statement)?); results.push(return_value); } Statement::Definition(statement) => { - self.enforce_definition_statement(cs, file_scope, function_scope, statement)?; + self.enforce_definition_statement(cs, statement)?; } Statement::Assign(statement) => { - self.enforce_assign_statement( - cs, - file_scope, - function_scope, - declared_circuit_reference, - indicator, - mut_self, - statement, - )?; + self.enforce_assign_statement(cs, indicator, statement)?; } Statement::Conditional(statement) => { - let result = self.enforce_conditional_statement( - cs, - file_scope, - function_scope, - indicator, - return_type, - declared_circuit_reference, - mut_self, - statement, - )?; + let result = self.enforce_conditional_statement(cs, indicator, statement)?; results.extend(result); } Statement::Iteration(statement) => { - let result = self.enforce_iteration_statement( - cs, - file_scope, - function_scope, - indicator, - return_type, - declared_circuit_reference, - mut_self, - statement, - )?; + let result = self.enforce_iteration_statement(cs, indicator, statement)?; results.extend(result); } Statement::Console(statement) => { - self.evaluate_console_function_call(cs, file_scope, function_scope, indicator, statement)?; + self.evaluate_console_function_call(cs, indicator, statement)?; } Statement::Expression(statement) => { - let expression_string = statement.expression.to_string(); - let value = self.enforce_expression(cs, file_scope, function_scope, None, statement.expression)?; + let value = self.enforce_expression(cs, &statement.expression)?; // handle empty return value cases match &value { ConstrainedValue::Tuple(values) => { @@ -113,20 +79,20 @@ impl> ConstrainedProgram { results.push((*indicator, value)); } } - _ => return Err(StatementError::unassigned(expression_string, statement.span)), + _ => { + 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) => { - let span = statement.span.clone(); + let span = statement.span.clone().unwrap_or_default(); let result = self.evaluate_block( &mut cs.ns(|| format!("block {}:{}", &span.line, &span.start)), - file_scope, - function_scope, indicator, statement, - return_type, - declared_circuit_reference, - mut_self, )?; results.extend(result); diff --git a/compiler/src/value/boolean/input.rs b/compiler/src/value/boolean/input.rs index 7fc30aaea9..cbced4ff02 100644 --- a/compiler/src/value/boolean/input.rs +++ b/compiler/src/value/boolean/input.rs @@ -28,14 +28,6 @@ use snarkvm_models::{ }, }; -pub(crate) fn new_bool_constant(string: String, span: &Span) -> Result { - let boolean = string - .parse::() - .map_err(|_| BooleanError::invalid_boolean(string, span.to_owned()))?; - - Ok(Boolean::constant(boolean)) -} - pub(crate) fn allocate_bool>( cs: &mut CS, name: &str, diff --git a/compiler/src/value/group/group_type.rs b/compiler/src/value/group/group_type.rs index 183c20fc63..730f6540c0 100644 --- a/compiler/src/value/group/group_type.rs +++ b/compiler/src/value/group/group_type.rs @@ -17,7 +17,7 @@ //! A data type that represents members in the group formed by the set of affine points on a curve. use crate::errors::GroupError; -use leo_ast::{GroupValue, Span}; +use leo_asg::{GroupValue, Span}; use snarkvm_models::{ curves::{Field, One}, @@ -48,7 +48,7 @@ pub trait GroupType: + ToBitsGadget + ToBytesGadget { - fn constant(value: GroupValue) -> Result; + fn constant(value: &GroupValue, span: &Span) -> Result; fn to_allocated>(&self, cs: CS, span: &Span) -> Result; diff --git a/compiler/src/value/group/input.rs b/compiler/src/value/group/input.rs index 62a613d263..a77db5e0fa 100644 --- a/compiler/src/value/group/input.rs +++ b/compiler/src/value/group/input.rs @@ -17,7 +17,8 @@ //! Methods to enforce constraints on input group values in a Leo program. use crate::{errors::GroupError, ConstrainedValue, GroupType}; -use leo_ast::{GroupValue, InputValue, Span}; +use leo_asg::{GroupValue, Span}; +use leo_ast::InputValue; use snarkvm_errors::gadgets::SynthesisError; use snarkvm_models::{ @@ -56,7 +57,15 @@ pub(crate) fn group_from_input, CS: Const None => None, }; - let group = allocate_group(cs, name, option, span)?; + let group = allocate_group( + cs, + name, + option.map(|x| match x { + leo_ast::GroupValue::Single(s, _) => GroupValue::Single(s), + leo_ast::GroupValue::Tuple(leo_ast::GroupTuple { x, y, .. }) => GroupValue::Tuple((&x).into(), (&y).into()), + }), + span, + )?; Ok(ConstrainedValue::Group(group)) } diff --git a/compiler/src/value/group/targets/edwards_bls12.rs b/compiler/src/value/group/targets/edwards_bls12.rs index 3b14ba9251..8ff4e4d81e 100644 --- a/compiler/src/value/group/targets/edwards_bls12.rs +++ b/compiler/src/value/group/targets/edwards_bls12.rs @@ -15,7 +15,7 @@ // along with the Leo library. If not, see . use crate::{errors::GroupError, GroupType}; -use leo_ast::{GroupCoordinate, GroupTuple, GroupValue, Span}; +use leo_asg::{GroupCoordinate, GroupValue, Span}; use snarkvm_curves::{ edwards_bls12::{EdwardsAffine, EdwardsParameters, Fq}, @@ -52,8 +52,8 @@ pub enum EdwardsGroupType { } impl GroupType for EdwardsGroupType { - fn constant(group: GroupValue) -> Result { - let value = Self::edwards_affine_from_value(group)?; + fn constant(group: &GroupValue, span: &Span) -> Result { + let value = Self::edwards_affine_from_value(group, span)?; Ok(EdwardsGroupType::Constant(value)) } @@ -134,75 +134,79 @@ impl GroupType for EdwardsGroupType { } impl EdwardsGroupType { - pub fn edwards_affine_from_value(value: GroupValue) -> Result { + pub fn edwards_affine_from_value(value: &GroupValue, span: &Span) -> Result { match value { - GroupValue::Single(number, span) => Self::edwards_affine_from_single(number, span), - GroupValue::Tuple(tuple) => Self::edwards_affine_from_tuple(tuple), + GroupValue::Single(number, ..) => Self::edwards_affine_from_single(number, span), + GroupValue::Tuple(x, y) => Self::edwards_affine_from_tuple(x, y, span), } } - pub fn edwards_affine_from_single(number: String, span: Span) -> Result { + pub fn edwards_affine_from_single(number: &str, span: &Span) -> Result { if number.eq("0") { Ok(EdwardsAffine::zero()) } else { let one = edwards_affine_one(); - let number_value = Fp256::from_str(&number).map_err(|_| GroupError::n_group(number, span))?; + let number_value = + Fp256::from_str(&number).map_err(|_| GroupError::n_group(number.to_string(), span.clone()))?; let result: EdwardsAffine = one.mul(&number_value); Ok(result) } } - pub fn edwards_affine_from_tuple(group: GroupTuple) -> Result { - let span = group.span; - let x = group.x; - let y = group.y; + pub fn edwards_affine_from_tuple( + x: &GroupCoordinate, + y: &GroupCoordinate, + span: &Span, + ) -> Result { + let x = x.clone(); + let y = y.clone(); match (x, y) { // (x, y) - (GroupCoordinate::Number(x_string, x_span), GroupCoordinate::Number(y_string, y_span)) => { - Self::edwards_affine_from_pair(x_string, y_string, x_span, y_span, span) + (GroupCoordinate::Number(x_string), GroupCoordinate::Number(y_string)) => { + Self::edwards_affine_from_pair(x_string, y_string, span, span, span) } // (x, +) - (GroupCoordinate::Number(x_string, x_span), GroupCoordinate::SignHigh) => { - Self::edwards_affine_from_x_str(x_string, x_span, Some(true), span) + (GroupCoordinate::Number(x_string), GroupCoordinate::SignHigh) => { + Self::edwards_affine_from_x_str(x_string, span, Some(true), span) } // (x, -) - (GroupCoordinate::Number(x_string, x_span), GroupCoordinate::SignLow) => { - Self::edwards_affine_from_x_str(x_string, x_span, Some(false), span) + (GroupCoordinate::Number(x_string), GroupCoordinate::SignLow) => { + Self::edwards_affine_from_x_str(x_string, span, Some(false), span) } // (x, _) - (GroupCoordinate::Number(x_string, x_span), GroupCoordinate::Inferred) => { - Self::edwards_affine_from_x_str(x_string, x_span, None, span) + (GroupCoordinate::Number(x_string), GroupCoordinate::Inferred) => { + Self::edwards_affine_from_x_str(x_string, span, None, span) } // (+, y) - (GroupCoordinate::SignHigh, GroupCoordinate::Number(y_string, y_span)) => { - Self::edwards_affine_from_y_str(y_string, y_span, Some(true), span) + (GroupCoordinate::SignHigh, GroupCoordinate::Number(y_string)) => { + Self::edwards_affine_from_y_str(y_string, span, Some(true), span) } // (-, y) - (GroupCoordinate::SignLow, GroupCoordinate::Number(y_string, y_span)) => { - Self::edwards_affine_from_y_str(y_string, y_span, Some(false), span) + (GroupCoordinate::SignLow, GroupCoordinate::Number(y_string)) => { + Self::edwards_affine_from_y_str(y_string, span, Some(false), span) } // (_, y) - (GroupCoordinate::Inferred, GroupCoordinate::Number(y_string, y_span)) => { - Self::edwards_affine_from_y_str(y_string, y_span, None, span) + (GroupCoordinate::Inferred, GroupCoordinate::Number(y_string)) => { + 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 +221,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 +252,7 @@ impl EdwardsGroupType { } // Otherwise return error. - Err(GroupError::y_recover(element_span)) + Err(GroupError::y_recover(element_span.clone())) } } } @@ -256,19 +260,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())) } } @@ -283,7 +287,7 @@ impl EdwardsGroupType { _ => Err(SynthesisError::AssignmentMissing), }?; - Self::edwards_affine_from_value(group_value).map_err(|_| SynthesisError::AssignmentMissing) + Self::edwards_affine_from_value(&group_value, &Span::default()).map_err(|_| SynthesisError::AssignmentMissing) } pub fn allocated>(&self, mut cs: CS) -> Result { diff --git a/compiler/src/value/implicit/implicit.rs b/compiler/src/value/implicit/implicit.rs deleted file mode 100644 index 2f042db5dc..0000000000 --- a/compiler/src/value/implicit/implicit.rs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (C) 2019-2021 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 . - -//! Enforces constraints on an implicit number in a compiled Leo program. - -use crate::{errors::ValueError, value::ConstrainedValue, GroupType}; -use leo_ast::{Span, Type}; - -use snarkvm_models::curves::{Field, PrimeField}; - -pub fn enforce_number_implicit>( - expected_type: Option, - value: String, - span: &Span, -) -> Result, ValueError> { - match expected_type { - Some(type_) => Ok(ConstrainedValue::from_type(value, &type_, span)?), - None => Ok(ConstrainedValue::Unresolved(value)), - } -} diff --git a/compiler/src/value/implicit/mod.rs b/compiler/src/value/implicit/mod.rs deleted file mode 100644 index e9d1ba7b7a..0000000000 --- a/compiler/src/value/implicit/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (C) 2019-2021 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 . - -pub mod implicit; -pub use self::implicit::*; diff --git a/compiler/src/value/integer/integer.rs b/compiler/src/value/integer/integer.rs index cc87d840c7..8386ffb2ff 100644 --- a/compiler/src/value/integer/integer.rs +++ b/compiler/src/value/integer/integer.rs @@ -16,7 +16,8 @@ //! Conversion of integer declarations to constraints in Leo. use crate::{errors::IntegerError, IntegerTrait}; -use leo_ast::{InputValue, IntegerType, Span, Type}; +use leo_asg::{ConstInt, IntegerType, Span}; +use leo_ast::InputValue; use leo_gadgets::{ arithmetic::*, bits::comparator::{ComparatorGadget, EvaluateLtGadget}, @@ -72,112 +73,18 @@ impl Integer { /// /// Checks that the expression is equal to the expected type if given. /// - pub fn new( - expected_type: Option, - actual_integer_type: &IntegerType, - string: String, - span: &Span, - ) -> Result { - // Check expected type if given. - if let Some(type_) = expected_type { - // Check expected type is an integer. - match type_ { - Type::IntegerType(expected_integer_type) => { - // Check expected integer type == actual integer type - if expected_integer_type.ne(actual_integer_type) { - return Err(IntegerError::invalid_integer_type( - &expected_integer_type, - actual_integer_type, - span.to_owned(), - )); - } - } - type_ => return Err(IntegerError::invalid_type(&type_, span.to_owned())), - } - } - - // Return a new constant integer. - Self::new_constant(actual_integer_type, string, span) - } - - /// - /// Returns a new integer value from an expression. - /// - /// The returned integer value is "constant" and is not allocated in the constraint system. - /// - pub fn new_constant(integer_type: &IntegerType, string: String, span: &Span) -> Result { - match integer_type { - IntegerType::U8 => { - let number = string - .parse::() - .map_err(|_| IntegerError::invalid_integer(string, span.to_owned()))?; - - Ok(Integer::U8(UInt8::constant(number))) - } - IntegerType::U16 => { - let number = string - .parse::() - .map_err(|_| IntegerError::invalid_integer(string, span.to_owned()))?; - - Ok(Integer::U16(UInt16::constant(number))) - } - IntegerType::U32 => { - let number = string - .parse::() - .map_err(|_| IntegerError::invalid_integer(string, span.to_owned()))?; - - Ok(Integer::U32(UInt32::constant(number))) - } - IntegerType::U64 => { - let number = string - .parse::() - .map_err(|_| IntegerError::invalid_integer(string, span.to_owned()))?; - - Ok(Integer::U64(UInt64::constant(number))) - } - IntegerType::U128 => { - let number = string - .parse::() - .map_err(|_| IntegerError::invalid_integer(string, span.to_owned()))?; - - Ok(Integer::U128(UInt128::constant(number))) - } - - IntegerType::I8 => { - let number = string - .parse::() - .map_err(|_| IntegerError::invalid_integer(string, span.to_owned()))?; - - Ok(Integer::I8(Int8::constant(number))) - } - IntegerType::I16 => { - let number = string - .parse::() - .map_err(|_| IntegerError::invalid_integer(string, span.to_owned()))?; - - Ok(Integer::I16(Int16::constant(number))) - } - IntegerType::I32 => { - let number = string - .parse::() - .map_err(|_| IntegerError::invalid_integer(string, span.to_owned()))?; - - Ok(Integer::I32(Int32::constant(number))) - } - IntegerType::I64 => { - let number = string - .parse::() - .map_err(|_| IntegerError::invalid_integer(string, span.to_owned()))?; - - Ok(Integer::I64(Int64::constant(number))) - } - IntegerType::I128 => { - let number = string - .parse::() - .map_err(|_| IntegerError::invalid_integer(string, span.to_owned()))?; - - Ok(Integer::I128(Int128::constant(number))) - } + pub fn new(value: &ConstInt) -> Self { + match value { + ConstInt::U8(i) => Integer::U8(UInt8::constant(*i)), + ConstInt::U16(i) => Integer::U16(UInt16::constant(*i)), + ConstInt::U32(i) => Integer::U32(UInt32::constant(*i)), + ConstInt::U64(i) => Integer::U64(UInt64::constant(*i)), + ConstInt::U128(i) => Integer::U128(UInt128::constant(*i)), + ConstInt::I8(i) => Integer::I8(Int8::constant(*i)), + ConstInt::I16(i) => Integer::I16(Int16::constant(*i)), + ConstInt::I32(i) => Integer::I32(Int32::constant(*i)), + ConstInt::I64(i) => Integer::I64(Int64::constant(*i)), + ConstInt::I128(i) => Integer::I128(Int128::constant(*i)), } } @@ -220,7 +127,7 @@ impl Integer { pub fn allocate_type>( cs: &mut CS, - integer_type: IntegerType, + integer_type: &IntegerType, name: &str, option: Option, span: &Span, @@ -371,7 +278,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/mod.rs b/compiler/src/value/mod.rs index b03dfb0064..384ab2f797 100644 --- a/compiler/src/value/mod.rs +++ b/compiler/src/value/mod.rs @@ -27,9 +27,6 @@ pub use self::field::*; pub mod group; pub use self::group::*; -pub mod implicit; -pub use self::implicit::*; - pub mod integer; pub use self::integer::*; diff --git a/compiler/src/value/value.rs b/compiler/src/value/value.rs index 933bad3c61..669c58a9f2 100644 --- a/compiler/src/value/value.rs +++ b/compiler/src/value/value.rs @@ -16,18 +16,8 @@ //! The in memory stored value for a defined name in a compiled Leo program. -use crate::{ - boolean::input::{allocate_bool, new_bool_constant}, - errors::{ExpressionError, FieldError, ValueError}, - is_in_scope, - new_scope, - Address, - FieldType, - GroupType, - Integer, -}; -use leo_ast::{ArrayDimensions, Circuit, Function, GroupValue, Identifier, Span, Type}; -use leo_core::Value; +use crate::{errors::ValueError, Address, FieldType, GroupType, Integer}; +use leo_asg::{CircuitBody, Identifier, Span, Type}; use snarkvm_errors::gadgets::SynthesisError; use snarkvm_models::{ @@ -37,7 +27,7 @@ use snarkvm_models::{ utilities::{boolean::Boolean, eq::ConditionalEqGadget, select::CondSelectGadget}, }, }; -use std::fmt; +use std::{fmt, sync::Arc}; #[derive(Clone, PartialEq, Eq)] pub struct ConstrainedCircuitMember>(pub Identifier, pub ConstrainedValue); @@ -58,50 +48,13 @@ pub enum ConstrainedValue> { Tuple(Vec>), // Circuits - CircuitDefinition(Circuit), - CircuitExpression(Identifier, Vec>), - - // Functions - Function(Option, Box), // (optional circuit identifier, function definition) + CircuitExpression(Arc, Vec>), // Modifiers Mutable(Box>), - Static(Box>), - Unresolved(String), - - // Imports - Import(String, Box>), } impl> ConstrainedValue { - pub(crate) fn from_other(value: String, other: &ConstrainedValue, span: &Span) -> Result { - let other_type = other.to_type(span)?; - - ConstrainedValue::from_type(value, &other_type, span) - } - - pub(crate) fn from_type(value: String, type_: &Type, span: &Span) -> Result { - match type_ { - // Data types - Type::Address => Ok(ConstrainedValue::Address(Address::constant(value, span)?)), - Type::Boolean => Ok(ConstrainedValue::Boolean(new_bool_constant(value, span)?)), - Type::Field => Ok(ConstrainedValue::Field(FieldType::constant(value, span)?)), - Type::Group => Ok(ConstrainedValue::Group(G::constant(GroupValue::Single( - value, - span.to_owned(), - ))?)), - Type::IntegerType(integer_type) => Ok(ConstrainedValue::Integer(Integer::new_constant( - integer_type, - value, - span, - )?)), - - // Data type wrappers - Type::Array(ref type_, _dimensions) => ConstrainedValue::from_type(value, type_, span), - _ => Ok(ConstrainedValue::Unresolved(value)), - } - } - pub(crate) fn to_type(&self, span: &Span) -> Result { Ok(match self { // Data types @@ -109,21 +62,13 @@ impl> ConstrainedValue { ConstrainedValue::Boolean(_bool) => Type::Boolean, ConstrainedValue::Field(_field) => Type::Field, ConstrainedValue::Group(_group) => Type::Group, - ConstrainedValue::Integer(integer) => Type::IntegerType(integer.get_type()), + ConstrainedValue::Integer(integer) => Type::Integer(integer.get_type()), // Data type wrappers ConstrainedValue::Array(array) => { let array_type = array[0].to_type(span)?; - let mut dimensions = ArrayDimensions::default(); - dimensions.push_usize(array.len()); - // Nested array type - if let Type::Array(inner_type, inner_dimensions) = &array_type { - dimensions.append(&mut inner_dimensions.clone()); - return Ok(Type::Array(inner_type.clone(), dimensions)); - } - - Type::Array(Box::new(array_type), dimensions) + Type::Array(Box::new(array_type), array.len()) } ConstrainedValue::Tuple(tuple) => { let mut types = Vec::with_capacity(tuple.len()); @@ -135,100 +80,11 @@ impl> ConstrainedValue { Type::Tuple(types) } - ConstrainedValue::CircuitExpression(id, _members) => Type::Circuit(id.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())), }) } - /// Returns the `ConstrainedValue` in intermediate `Value` format (for core circuits) - pub(crate) fn to_value(&self) -> Value { - match self.clone() { - ConstrainedValue::Boolean(boolean) => Value::Boolean(boolean), - ConstrainedValue::Integer(integer) => match integer { - Integer::U8(u8) => Value::U8(u8), - Integer::U16(u16) => Value::U16(u16), - Integer::U32(u32) => Value::U32(u32), - Integer::U64(u64) => Value::U64(u64), - Integer::U128(u128) => Value::U128(u128), - - Integer::I8(i8) => Value::I8(i8), - Integer::I16(i16) => Value::I16(i16), - Integer::I32(i32) => Value::I32(i32), - Integer::I64(i64) => Value::I64(i64), - Integer::I128(i128) => Value::I128(i128), - }, - ConstrainedValue::Array(array) => { - let array_value = array.into_iter().map(|element| element.to_value()).collect(); - - Value::Array(array_value) - } - ConstrainedValue::Tuple(tuple) => { - let tuple_value = tuple.into_iter().map(|element| element.to_value()).collect(); - - Value::Tuple(tuple_value) - } - _ => unimplemented!(), - } - } - - pub(crate) fn resolve_type(&mut self, type_: Option, span: &Span) -> Result<(), ValueError> { - if let ConstrainedValue::Unresolved(ref string) = self { - if type_.is_some() { - *self = ConstrainedValue::from_type(string.clone(), &type_.unwrap(), span)? - } - } - - Ok(()) - } - - /// Expect both `self` and `other` to resolve to the same type - pub(crate) fn resolve_types( - &mut self, - other: &mut Self, - type_: Option, - span: &Span, - ) -> Result<(), ValueError> { - if type_.is_some() { - self.resolve_type(type_.clone(), span)?; - return other.resolve_type(type_, span); - } - - match (&self, &other) { - (ConstrainedValue::Unresolved(_), ConstrainedValue::Unresolved(_)) => Ok(()), - (ConstrainedValue::Unresolved(_), _) => self.resolve_type(Some(other.to_type(span)?), span), - (_, ConstrainedValue::Unresolved(_)) => other.resolve_type(Some(self.to_type(span)?), span), - _ => Ok(()), - } - } - - pub(crate) fn extract_function(self, scope: &str, span: &Span) -> Result<(String, Function), ExpressionError> { - match self { - ConstrainedValue::Function(circuit_identifier, function) => { - let mut outer_scope = scope.to_string(); - // If this is a circuit function, evaluate inside the circuit scope - if let Some(identifier) = circuit_identifier { - // avoid creating recursive scope - if !is_in_scope(&scope, &identifier.name) { - outer_scope = new_scope(scope, &identifier.name); - } - } - - Ok((outer_scope, *function)) - } - ConstrainedValue::Import(import_scope, function) => function.extract_function(&import_scope, span), - value => Err(ExpressionError::undefined_function(value.to_string(), span.to_owned())), - } - } - - pub(crate) fn extract_circuit(self, span: &Span) -> Result { - match self { - ConstrainedValue::CircuitDefinition(circuit) => Ok(circuit), - ConstrainedValue::Import(_import_scope, circuit) => circuit.extract_circuit(span), - value => Err(ExpressionError::undefined_circuit(value.to_string(), span.to_owned())), - } - } - /// /// Modifies the `self` [ConstrainedValue] so there are no `mut` keywords wrapping the `self` value. /// @@ -241,85 +97,6 @@ impl> ConstrainedValue { *self = *inner.clone() } } - - pub(crate) fn allocate_value>( - &mut self, - mut cs: CS, - span: &Span, - ) -> Result<(), ValueError> { - match self { - // Data types - ConstrainedValue::Address(_address) => { - // allow `let address()` even though addresses are constant - } - ConstrainedValue::Boolean(boolean) => { - let option = boolean.get_value(); - let name = option - .map(|b| b.to_string()) - .unwrap_or_else(|| "[allocated]".to_string()); - - *boolean = allocate_bool(&mut cs, &name, option, span)?; - } - ConstrainedValue::Field(field) => { - let gadget = field - .allocated(cs.ns(|| format!("allocate field {}:{}", span.line, span.start))) - .map_err(|error| ValueError::FieldError(FieldError::synthesis_error(error, span.to_owned())))?; - - *field = FieldType::Allocated(gadget) - } - ConstrainedValue::Group(group) => { - *group = group.to_allocated(cs, span)?; - } - ConstrainedValue::Integer(integer) => { - let integer_type = integer.get_type(); - 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)?; - } - - // Data type wrappers - ConstrainedValue::Array(array) => { - array.iter_mut().enumerate().try_for_each(|(i, value)| { - let unique_name = format!("allocate array member {} {}:{}", i, span.line, span.start); - - value.allocate_value(cs.ns(|| unique_name), span) - })?; - } - ConstrainedValue::Tuple(tuple) => { - tuple.iter_mut().enumerate().try_for_each(|(i, value)| { - let unique_name = format!("allocate tuple member {} {}:{}", i, span.line, span.start); - - value.allocate_value(cs.ns(|| unique_name), span) - })?; - } - 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); - - member.1.allocate_value(cs.ns(|| unique_name), span) - })?; - } - ConstrainedValue::Mutable(value) => { - value.allocate_value(cs, span)?; - } - ConstrainedValue::Static(value) => { - value.allocate_value(cs, span)?; - } - - // Empty wrappers that are unreachable - ConstrainedValue::CircuitDefinition(_) => {} - ConstrainedValue::Function(_, _) => {} - ConstrainedValue::Import(_, _) => {} - - // Cannot allocate an unresolved value - ConstrainedValue::Unresolved(value) => { - return Err(ValueError::implicit(value.to_string(), span.to_owned())); - } - } - - Ok(()) - } } impl> fmt::Display for ConstrainedValue { @@ -355,8 +132,8 @@ impl> fmt::Display for ConstrainedValue { - write!(f, "{} {{", identifier)?; + 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)?; if i < members.len() - 1 { @@ -365,14 +142,7 @@ impl> fmt::Display for ConstrainedValue write!(f, "circuit {{ {} }}", circuit.circuit_name), - ConstrainedValue::Function(ref _circuit_option, ref function) => { - write!(f, "function {{ {}() }}", function.identifier) - } - ConstrainedValue::Import(_, ref value) => write!(f, "{}", value), ConstrainedValue::Mutable(ref value) => write!(f, "{}", value), - ConstrainedValue::Static(ref value) => write!(f, "{}", value), - ConstrainedValue::Unresolved(ref value) => write!(f, "{}", value), } } } @@ -478,11 +248,6 @@ impl> CondSelectGadget for Constrained ConstrainedValue::Tuple(array) } - (ConstrainedValue::Function(identifier_1, function_1), ConstrainedValue::Function(_, _)) => { - // This is a no-op. functions cannot hold circuit values - // However, we must return a result here - ConstrainedValue::Function(identifier_1.clone(), function_1.clone()) - } ( ConstrainedValue::CircuitExpression(identifier, members_1), ConstrainedValue::CircuitExpression(_identifier, members_2), @@ -500,11 +265,6 @@ impl> CondSelectGadget for Constrained ConstrainedValue::CircuitExpression(identifier.clone(), members) } - (ConstrainedValue::Static(first), ConstrainedValue::Static(second)) => { - let value = Self::conditionally_select(cs, cond, first, second)?; - - ConstrainedValue::Static(Box::new(value)) - } (ConstrainedValue::Mutable(first), _) => Self::conditionally_select(cs, cond, first, second)?, (_, ConstrainedValue::Mutable(second)) => Self::conditionally_select(cs, cond, first, second)?, (_, _) => return Err(SynthesisError::Unsatisfiable), @@ -533,25 +293,3 @@ impl> CondSelectGadget for Constrained unimplemented!() } } - -impl> From for ConstrainedValue { - fn from(v: Value) -> Self { - match v { - Value::Boolean(boolean) => ConstrainedValue::Boolean(boolean), - Value::U8(u8) => ConstrainedValue::Integer(Integer::U8(u8)), - Value::U16(u16) => ConstrainedValue::Integer(Integer::U16(u16)), - Value::U32(u32) => ConstrainedValue::Integer(Integer::U32(u32)), - Value::U64(u64) => ConstrainedValue::Integer(Integer::U64(u64)), - Value::U128(u128) => ConstrainedValue::Integer(Integer::U128(u128)), - - Value::I8(i8) => ConstrainedValue::Integer(Integer::I8(i8)), - Value::I16(i16) => ConstrainedValue::Integer(Integer::I16(i16)), - Value::I32(i32) => ConstrainedValue::Integer(Integer::I32(i32)), - Value::I64(i64) => ConstrainedValue::Integer(Integer::I64(i64)), - Value::I128(i128) => ConstrainedValue::Integer(Integer::I128(i128)), - - Value::Array(array) => ConstrainedValue::Array(array.into_iter().map(ConstrainedValue::from).collect()), - Value::Tuple(tuple) => ConstrainedValue::Tuple(tuple.into_iter().map(ConstrainedValue::from).collect()), - } - } -} diff --git a/compiler/tests/address/mod.rs b/compiler/tests/address/mod.rs index a43a485854..b0193ffbdf 100644 --- a/compiler/tests/address/mod.rs +++ b/compiler/tests/address/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, generate_main_input, parse_program}; +use crate::{assert_satisfied, expect_asg_error, expect_compiler_error, generate_main_input, parse_program}; use leo_ast::InputValue; static TEST_ADDRESS_1: &str = "aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8sta57j8"; @@ -63,9 +63,9 @@ fn test_implicit_valid() { #[test] fn test_implicit_invalid() { let program_string = include_str!("implicit_invalid.leo"); - let program = parse_program(program_string).unwrap(); + let error = parse_program(program_string).err().unwrap(); - let _output = expect_compiler_error(program); + expect_asg_error(error); } #[test] diff --git a/compiler/tests/array/mod.rs b/compiler/tests/array/mod.rs index d6e6742a00..fb01748d2f 100644 --- a/compiler/tests/array/mod.rs +++ b/compiler/tests/array/mod.rs @@ -16,6 +16,7 @@ use crate::{ assert_satisfied, + expect_asg_error, expect_compiler_error, get_output, parse_program, @@ -67,6 +68,14 @@ fn test_inline() { assert_satisfied(program); } +#[test] +fn test_nested() { + let program_string = include_str!("nested.leo"); + let program = parse_program(program_string).unwrap(); + + assert_satisfied(program); +} + #[test] fn test_inline_fail() { let program_string = include_str!("inline.leo"); @@ -150,17 +159,17 @@ fn test_input_tuple_3x2_fail() { #[test] fn test_multi_fail_initializer() { let program_string = include_str!("multi_fail_initializer.leo"); - let program = parse_program(program_string).unwrap(); + let error = parse_program(program_string).err().unwrap(); - let _err = expect_compiler_error(program); + expect_asg_error(error); } #[test] fn test_multi_inline_fail() { let program_string = include_str!("multi_fail_inline.leo"); - let program = parse_program(program_string).unwrap(); + let error = parse_program(program_string).err().unwrap(); - let _err = expect_compiler_error(program); + expect_asg_error(error); } #[test] @@ -174,9 +183,9 @@ fn test_multi_initializer() { #[test] fn test_multi_initializer_fail() { let program_string = include_str!("multi_initializer_fail.leo"); - let program = parse_program(program_string).unwrap(); + let error = parse_program(program_string).err().unwrap(); - let _err = expect_compiler_error(program); + expect_asg_error(error); } #[test] @@ -190,9 +199,9 @@ fn test_nested_3x2_value() { #[test] fn test_nested_3x2_value_fail() { let program_string = include_str!("nested_3x2_value_fail.leo"); - let program = parse_program(program_string).unwrap(); + let error = parse_program(program_string).err().unwrap(); - let _err = expect_compiler_error(program); + expect_asg_error(error); } #[test] @@ -206,9 +215,9 @@ fn test_tuple_3x2_value() { #[test] fn test_tuple_3x2_value_fail() { let program_string = include_str!("tuple_3x2_value_fail.leo"); - let program = parse_program(program_string).unwrap(); + let error = parse_program(program_string).err().unwrap(); - let _err = expect_compiler_error(program); + expect_asg_error(error); } #[test] @@ -258,9 +267,9 @@ fn test_type_nested_value_nested_3x2() { #[test] fn test_type_nested_value_nested_3x2_fail() { let program_string = include_str!("type_nested_value_nested_3x2_fail.leo"); - let program = parse_program(program_string).unwrap(); + let error = parse_program(program_string).err().unwrap(); - let _err = expect_compiler_error(program); + expect_asg_error(error); } #[test] @@ -274,9 +283,9 @@ fn test_type_nested_value_nested_4x3x2() { #[test] fn test_type_nested_value_nested_4x3x2_fail() { let program_string = include_str!("type_nested_value_nested_4x3x2_fail.leo"); - let program = parse_program(program_string).unwrap(); + let error = parse_program(program_string).err().unwrap(); - let _err = expect_compiler_error(program); + expect_asg_error(error); } #[test] @@ -290,9 +299,9 @@ fn test_type_nested_value_tuple_3x2() { #[test] fn test_type_nested_value_tuple_3x2_fail() { let program_string = include_str!("type_nested_value_tuple_3x2_fail.leo"); - let program = parse_program(program_string).unwrap(); + let error = parse_program(program_string).err().unwrap(); - let _err = expect_compiler_error(program); + expect_asg_error(error); } #[test] @@ -306,9 +315,9 @@ fn test_type_nested_value_tuple_4x3x2() { #[test] fn test_type_nested_value_tuple_4x3x2_fail() { let program_string = include_str!("type_nested_value_tuple_4x3x2_fail.leo"); - let program = parse_program(program_string).unwrap(); + let error = parse_program(program_string).err().unwrap(); - let _err = expect_compiler_error(program); + expect_asg_error(error); } #[test] @@ -322,9 +331,9 @@ fn test_type_tuple_value_nested_3x2() { #[test] fn test_type_tuple_value_nested_3x2_fail() { let program_string = include_str!("type_tuple_value_nested_3x2_fail.leo"); - let program = parse_program(program_string).unwrap(); + let error = parse_program(program_string).err().unwrap(); - let _err = expect_compiler_error(program); + expect_asg_error(error); } #[test] @@ -338,9 +347,9 @@ fn test_type_tuple_value_nested_4x3x2() { #[test] fn test_type_tuple_value_nested_4x3x2_fail() { let program_string = include_str!("type_tuple_value_nested_4x3x2_fail.leo"); - let program = parse_program(program_string).unwrap(); + let error = parse_program(program_string).err().unwrap(); - let _err = expect_compiler_error(program); + expect_asg_error(error); } #[test] @@ -354,9 +363,9 @@ fn test_type_tuple_value_tuple_3x2() { #[test] fn test_type_tuple_value_tuple_3x2_fail() { let program_string = include_str!("type_tuple_value_tuple_3x2_fail.leo"); - let program = parse_program(program_string).unwrap(); + let error = parse_program(program_string).err().unwrap(); - let _err = expect_compiler_error(program); + expect_asg_error(error); } #[test] @@ -370,9 +379,9 @@ fn test_type_tuple_value_tuple_4x3x2() { #[test] fn test_type_tuple_value_tuple_4x3x2_fail() { let program_string = include_str!("type_tuple_value_tuple_4x3x2_fail.leo"); - let program = parse_program(program_string).unwrap(); + let error = parse_program(program_string).err().unwrap(); - let _err = expect_compiler_error(program); + expect_asg_error(error); } // Tests for nested multi-dimensional arrays as input to the program @@ -522,3 +531,11 @@ fn test_input_type_tuple_value_tuple_4x3x2_fail() { assert!(syntax_error); } + +#[test] +fn test_variable_slice_fail() { + let program_string = include_str!("variable_slice_fail.leo"); + let error = parse_program(program_string).err().unwrap(); + + expect_asg_error(error); +} diff --git a/compiler/tests/array/nested.leo b/compiler/tests/array/nested.leo new file mode 100644 index 0000000000..c557758b05 --- /dev/null +++ b/compiler/tests/array/nested.leo @@ -0,0 +1,4 @@ +function main () { + let x = [false; (2, 2)]; + let y: bool = x[0][0]; +} diff --git a/compiler/tests/array/type_tuple_value_nested_3x2.leo b/compiler/tests/array/type_tuple_value_nested_3x2.leo index 0b960c6b44..81195e03a1 100644 --- a/compiler/tests/array/type_tuple_value_nested_3x2.leo +++ b/compiler/tests/array/type_tuple_value_nested_3x2.leo @@ -1,7 +1,7 @@ function main() { const a = [[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]]; // inline - const b: [u8; (2, 3)] = [[0; 3]; 2]; // initializer + const b: [u8; (3, 2)] = [[0; 2]; 3]; // initializer console.assert(a == b); } \ No newline at end of file diff --git a/compiler/tests/array/type_tuple_value_tuple_3x2.leo b/compiler/tests/array/type_tuple_value_tuple_3x2.leo index d742a544a7..d451a9c1a8 100644 --- a/compiler/tests/array/type_tuple_value_tuple_3x2.leo +++ b/compiler/tests/array/type_tuple_value_tuple_3x2.leo @@ -1,7 +1,7 @@ function main() { const a = [[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]]; // inline - const b: [u8; (2, 3)] = [0; (2, 3)]; // initializer + const b: [u8; (3, 2)] = [0; (3, 2)]; // initializer console.assert(a == b); } \ No newline at end of file diff --git a/compiler/tests/array/variable_slice_fail.leo b/compiler/tests/array/variable_slice_fail.leo new file mode 100644 index 0000000000..edb04caacf --- /dev/null +++ b/compiler/tests/array/variable_slice_fail.leo @@ -0,0 +1,7 @@ +function main() { + let a = [1u8; 10]; + for i in 0..10 { + let x = a[i..10]; + console.debug("{}", x); + } +} \ No newline at end of file diff --git a/compiler/tests/boolean/mod.rs b/compiler/tests/boolean/mod.rs index e6d34cecca..20cb0d787f 100644 --- a/compiler/tests/boolean/mod.rs +++ b/compiler/tests/boolean/mod.rs @@ -16,8 +16,8 @@ use crate::{ assert_satisfied, + expect_asg_error, expect_compiler_error, - expect_type_inference_error, get_output, parse_program, parse_program_with_input, @@ -104,9 +104,9 @@ fn test_not_mutable() { #[test] fn test_not_u32() { let program_string = include_str!("not_u32.leo"); - let program = parse_program(program_string).unwrap(); + let error = parse_program(program_string).err().unwrap(); - expect_compiler_error(program); + expect_asg_error(error); } // Boolean or || @@ -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/member_function.leo b/compiler/tests/circuits/member_function.leo index 024b0d7e02..e40603dffb 100644 --- a/compiler/tests/circuits/member_function.leo +++ b/compiler/tests/circuits/member_function.leo @@ -1,11 +1,13 @@ circuit Foo { - function echo(x: u32) -> u32 { - return x + x: u32, + + function echo(self) -> u32 { + return self.x } } function main() { - let a = Foo { }; + let a = Foo { x: 1u32 }; - console.assert(a.echo(1u32) == 1u32); + console.assert(a.echo() == 1u32); } \ No newline at end of file diff --git a/compiler/tests/circuits/mod.rs b/compiler/tests/circuits/mod.rs index 94792cc190..dbed6c7e41 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_asg_error, parse_program}; // Expressions @@ -29,9 +29,9 @@ fn test_inline() { #[test] fn test_inline_fail() { let program_string = include_str!("inline_fail.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] @@ -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] @@ -150,6 +150,14 @@ fn test_mutate_self_variable() { assert_satisfied(program); } +#[test] +fn test_mutate_self_variable_branch() { + let program_string = include_str!("mut_self_variable_branch.leo"); + let program = parse_program(program_string).unwrap(); + + assert_satisfied(program); +} + #[test] fn test_mutate_self_variable_conditional() { let program_string = include_str!("mut_self_variable_conditional.leo"); @@ -161,9 +169,9 @@ fn test_mutate_self_variable_conditional() { #[test] fn test_mutate_self_variable_fail() { let program_string = include_str!("mut_self_variable_fail.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] @@ -171,7 +179,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 +187,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 +195,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] @@ -201,9 +209,9 @@ fn test_mutate_variable() { #[test] fn test_mutate_variable_fail() { let program_string = include_str!("mut_variable_fail.leo"); - let program = parse_program(program_string).unwrap(); + let error = parse_program(program_string).err().unwrap(); - expect_compiler_error(program); + expect_asg_error(error); } // Self @@ -213,7 +221,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 +237,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 +245,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/circuits/mut_self_variable_branch.leo b/compiler/tests/circuits/mut_self_variable_branch.leo new file mode 100644 index 0000000000..e47f9b85df --- /dev/null +++ b/compiler/tests/circuits/mut_self_variable_branch.leo @@ -0,0 +1,32 @@ +circuit Foo { + a: u8, + + function set_a(mut self, condition: bool, new: u8) { + if condition { + self.a = new; + console.assert(self.a == new); + } + } +} + +function main() { + let mut f = Foo { a: 0u8 }; + + console.assert(f.a == 0u8); + + f.set_a(false, 1u8); + + console.assert(f.a == 0u8); + + f.set_a(true, 1u8); + + console.assert(f.a == 1u8); + + f.set_a(false, 2u8); + + console.assert(f.a == 1u8); + + f.set_a(true, 2u8); + + console.assert(f.a == 2u8); +} \ No newline at end of file diff --git a/compiler/tests/console/mod.rs b/compiler/tests/console/mod.rs index 520a3681cd..62ff5bce6f 100644 --- a/compiler/tests/console/mod.rs +++ b/compiler/tests/console/mod.rs @@ -14,7 +14,14 @@ // 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, generate_main_input, parse_program, parse_program_with_input}; +use crate::{ + assert_satisfied, + expect_asg_error, + expect_compiler_error, + generate_main_input, + parse_program, + parse_program_with_input, +}; use leo_ast::InputValue; #[test] @@ -48,28 +55,28 @@ fn test_log_parameter_many() { assert_satisfied(program); } -#[test] -fn test_log_parameter_fail_unknown() { - let program_string = include_str!("log_parameter_fail_unknown.leo"); - let program = parse_program(program_string).unwrap(); - - expect_compiler_error(program); -} - #[test] fn test_log_parameter_fail_empty() { let program_string = include_str!("log_parameter_fail_empty.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_log_parameter_fail_none() { let program_string = include_str!("log_parameter_fail_empty.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_log_parameter_fail_unknown() { + let program_string = include_str!("log_parameter_fail_unknown.leo"); + let error = parse_program(program_string).err().unwrap(); + + expect_asg_error(error); } #[test] diff --git a/compiler/tests/core/mod.rs b/compiler/tests/core/mod.rs index 871695f047..c4a6bb48a5 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 848b4dc3d3..b989fc5f6e 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 ce0429ba44..e9d116dc0b 100644 --- a/compiler/tests/function/mod.rs +++ b/compiler/tests/function/mod.rs @@ -14,15 +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, - get_output, - parse_program, - parse_program_with_input, -}; -use leo_compiler::errors::{CompilerError, ExpressionError, FunctionError, StatementError}; +use crate::{assert_satisfied, expect_asg_error, get_output, parse_program, parse_program_with_input}; #[test] fn test_empty() { @@ -72,17 +64,17 @@ fn test_multiple_returns() { #[test] fn test_multiple_returns_fail() { let program_string = include_str!("multiple_returns_fail.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_multiple_returns_fail_conditional() { let program_string = include_str!("multiple_returns_fail_conditional.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,17 +110,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 +120,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 +136,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 @@ -160,9 +144,9 @@ fn test_array_input() { #[test] fn test_return_array_nested_fail() { let program_string = include_str!("return_array_nested_fail.leo"); - let program = parse_program(program_string).unwrap(); + let error = parse_program(program_string).err().unwrap(); - let _err = expect_compiler_error(program); + expect_asg_error(error); } #[test] @@ -176,9 +160,9 @@ fn test_return_array_nested_pass() { #[test] fn test_return_array_tuple_fail() { let program_string = include_str!("return_array_tuple_fail.leo"); - let program = parse_program(program_string).unwrap(); + let error = parse_program(program_string).err().unwrap(); - let _err = expect_compiler_error(program); + expect_asg_error(error); } #[test] diff --git a/compiler/tests/input_files/program_input/input/main_array.in b/compiler/tests/input_files/program_input/input/main_array.in new file mode 100644 index 0000000000..34db280b2e --- /dev/null +++ b/compiler/tests/input_files/program_input/input/main_array.in @@ -0,0 +1,2 @@ +[main] +x: [i16; 1] = [0i16; 1]; diff --git a/compiler/tests/input_files/program_input/main_array.leo b/compiler/tests/input_files/program_input/main_array.leo new file mode 100644 index 0000000000..58acae24bf --- /dev/null +++ b/compiler/tests/input_files/program_input/main_array.leo @@ -0,0 +1,3 @@ +function main (x: [i16; 2]) { + console.log("{}", x); +} \ No newline at end of file diff --git a/compiler/tests/input_files/program_input/mod.rs b/compiler/tests/input_files/program_input/mod.rs index 7d7888a30c..6bd78e69e6 100644 --- a/compiler/tests/input_files/program_input/mod.rs +++ b/compiler/tests/input_files/program_input/mod.rs @@ -34,6 +34,16 @@ fn test_input_pass() { assert_satisfied(program); } +#[test] +fn test_input_array_fail() { + let program_string = include_str!("main_array.leo"); + let input_string = include_str!("input/main_array.in"); + + let program = parse_program_with_input(program_string, input_string).unwrap(); + + assert_satisfied(program); +} + #[test] fn test_input_fail_name() { let program_string = include_str!("main.leo"); diff --git a/compiler/tests/integers/i128/mod.rs b/compiler/tests/integers/i128/mod.rs index 1ff6b8ced3..e62e07260e 100644 --- a/compiler/tests/integers/i128/mod.rs +++ b/compiler/tests/integers/i128/mod.rs @@ -16,9 +16,10 @@ use crate::{ assert_satisfied, + expect_asg_error, expect_compiler_error, generate_main_input, - integers::{expect_computation_error, expect_parsing_error, IntegerTester}, + integers::{expect_computation_error, IntegerTester}, parse_program, }; use leo_ast::InputValue; diff --git a/compiler/tests/integers/i16/mod.rs b/compiler/tests/integers/i16/mod.rs index 3cd717e0c2..49b45f5b3e 100644 --- a/compiler/tests/integers/i16/mod.rs +++ b/compiler/tests/integers/i16/mod.rs @@ -16,9 +16,10 @@ use crate::{ assert_satisfied, + expect_asg_error, expect_compiler_error, generate_main_input, - integers::{expect_computation_error, expect_parsing_error, IntegerTester}, + integers::{expect_computation_error, IntegerTester}, parse_program, }; use leo_ast::InputValue; diff --git a/compiler/tests/integers/i32/mod.rs b/compiler/tests/integers/i32/mod.rs index ef13fb1efd..ee9e25701a 100644 --- a/compiler/tests/integers/i32/mod.rs +++ b/compiler/tests/integers/i32/mod.rs @@ -16,9 +16,10 @@ use crate::{ assert_satisfied, + expect_asg_error, expect_compiler_error, generate_main_input, - integers::{expect_computation_error, expect_parsing_error, IntegerTester}, + integers::{expect_computation_error, IntegerTester}, parse_program, }; use leo_ast::InputValue; diff --git a/compiler/tests/integers/i64/mod.rs b/compiler/tests/integers/i64/mod.rs index 36306198db..066ac9956f 100644 --- a/compiler/tests/integers/i64/mod.rs +++ b/compiler/tests/integers/i64/mod.rs @@ -16,9 +16,10 @@ use crate::{ assert_satisfied, + expect_asg_error, expect_compiler_error, generate_main_input, - integers::{expect_computation_error, expect_parsing_error, IntegerTester}, + integers::{expect_computation_error, IntegerTester}, parse_program, }; use leo_ast::InputValue; diff --git a/compiler/tests/integers/i8/mod.rs b/compiler/tests/integers/i8/mod.rs index 30cc71149d..9133a72248 100644 --- a/compiler/tests/integers/i8/mod.rs +++ b/compiler/tests/integers/i8/mod.rs @@ -16,9 +16,10 @@ use crate::{ assert_satisfied, + expect_asg_error, expect_compiler_error, generate_main_input, - integers::{expect_computation_error, expect_parsing_error, IntegerTester}, + integers::{expect_computation_error, IntegerTester}, parse_program, }; use leo_ast::InputValue; diff --git a/compiler/tests/integers/int_macro.rs b/compiler/tests/integers/int_macro.rs index 328db3aa3d..7867961fc4 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 b63ba7c7ef..23085d5aac 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 35f0df1714..2c110af0a5 100644 --- a/compiler/tests/integers/u128/mod.rs +++ b/compiler/tests/integers/u128/mod.rs @@ -16,9 +16,10 @@ use crate::{ assert_satisfied, + expect_asg_error, expect_compiler_error, generate_main_input, - integers::{expect_parsing_error, IntegerTester}, + integers::IntegerTester, parse_program, }; use leo_ast::InputValue; diff --git a/compiler/tests/integers/u16/mod.rs b/compiler/tests/integers/u16/mod.rs index d9738cea14..b4b202b9da 100644 --- a/compiler/tests/integers/u16/mod.rs +++ b/compiler/tests/integers/u16/mod.rs @@ -16,9 +16,10 @@ use crate::{ assert_satisfied, + expect_asg_error, expect_compiler_error, generate_main_input, - integers::{expect_parsing_error, IntegerTester}, + integers::IntegerTester, parse_program, }; use leo_ast::InputValue; diff --git a/compiler/tests/integers/u32/mod.rs b/compiler/tests/integers/u32/mod.rs index 90b9c06622..920fc6ed5b 100644 --- a/compiler/tests/integers/u32/mod.rs +++ b/compiler/tests/integers/u32/mod.rs @@ -16,9 +16,10 @@ use crate::{ assert_satisfied, + expect_asg_error, expect_compiler_error, generate_main_input, - integers::{expect_parsing_error, IntegerTester}, + integers::IntegerTester, parse_program, }; use leo_ast::InputValue; diff --git a/compiler/tests/integers/u64/mod.rs b/compiler/tests/integers/u64/mod.rs index be667c6c2f..ec86c868f1 100644 --- a/compiler/tests/integers/u64/mod.rs +++ b/compiler/tests/integers/u64/mod.rs @@ -16,9 +16,10 @@ use crate::{ assert_satisfied, + expect_asg_error, expect_compiler_error, generate_main_input, - integers::{expect_parsing_error, IntegerTester}, + integers::IntegerTester, parse_program, }; use leo_ast::InputValue; diff --git a/compiler/tests/integers/u8/mod.rs b/compiler/tests/integers/u8/mod.rs index b8e67b8a3b..a61e28246d 100644 --- a/compiler/tests/integers/u8/mod.rs +++ b/compiler/tests/integers/u8/mod.rs @@ -16,9 +16,10 @@ use crate::{ assert_satisfied, + expect_asg_error, expect_compiler_error, generate_main_input, - integers::{expect_parsing_error, IntegerTester}, + integers::IntegerTester, parse_program, }; use leo_ast::InputValue; diff --git a/compiler/tests/integers/uint_macro.rs b/compiler/tests/integers/uint_macro.rs index 8216a6f3b5..393ed1c7a6 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 58d48416bb..7c29d5add8 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 25bc66a498..8acd3f9e51 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] @@ -154,6 +149,7 @@ fn test_function_input_mut() { } #[test] +#[ignore] fn test_swap() { let program_string = include_str!("swap.leo"); let program = parse_program(program_string).unwrap(); 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 5bfcf845b6..3aeb3f858b 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 4a3962d438..2fb1a100ea 100644 --- a/compiler/tests/syntax/mod.rs +++ b/compiler/tests/syntax/mod.rs @@ -14,11 +14,10 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::{expect_compiler_error, parse_input, parse_program}; -use leo_compiler::errors::{CompilerError, ExpressionError, FunctionError, StatementError}; +use crate::{expect_asg_error, parse_input, parse_program}; +use leo_compiler::errors::CompilerError; use leo_grammar::ParserError; use leo_input::InputParserError; -use leo_type_inference::errors::{FrameError, TypeAssertionError, TypeInferenceError}; pub mod identifiers; @@ -37,29 +36,9 @@ fn test_semicolon() { #[test] fn test_undefined() { let program_string = include_str!("undefined.leo"); - let program = parse_program(program_string).unwrap(); + let error = parse_program(program_string).err().unwrap(); - let error = expect_compiler_error(program); - - match error { - CompilerError::FunctionError(FunctionError::StatementError(StatementError::ExpressionError( - ExpressionError::Error(error), - ))) => { - assert_eq!( - error.to_string(), - vec![ - " --> \"/test/src/main.leo\": 2:12", - " |", - " 2 | return a", - " | ^", - " |", - " = Cannot find value `a` in this scope", - ] - .join("\n") - ); - } - _ => panic!("expected an undefined identifier error"), - } + expect_asg_error(error); } #[test] @@ -80,10 +59,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/core/Cargo.toml b/core/Cargo.toml deleted file mode 100644 index ed0617219b..0000000000 --- a/core/Cargo.toml +++ /dev/null @@ -1,59 +0,0 @@ -[package] -name = "leo-core" -version = "1.0.8" -authors = [ "The Aleo Team " ] -description = "Core package dependencies of the Leo programming language" -homepage = "https://aleo.org" -repository = "https://github.com/AleoHQ/leo" -keywords = [ - "aleo", - "cryptography", - "leo", - "programming-language", - "zero-knowledge" -] -categories = [ "cryptography::cryptocurrencies", "web-programming" ] -include = [ "Cargo.toml", "src", "README.md", "LICENSE.md" ] -license = "GPL-3.0" -edition = "2018" - -[dependencies.leo-ast] -path = "../ast" -version = "1.0.8" - -[dependencies.leo-gadgets] -path = "../gadgets" -version = "1.0.8" - -[dependencies.snarkvm-errors] -version = "0.0.2" -default-features = false - -[dependencies.snarkvm-gadgets] -version = "0.0.2" -default-features = false - -[dependencies.snarkvm-models] -version = "0.0.2" -default-features = false - -[dependencies.snarkvm-utilities] -version = "0.0.2" - -[dependencies.rand] -version = "0.7" -default-features = false - -[dependencies.rand_xorshift] -version = "0.2" -default-features = false - -[dependencies.thiserror] -version = "1.0" - -[dev-dependencies.snarkvm-utilities] -version = "0.0.2" - -[dev-dependencies.snarkvm-curves] -version = "0.0.2" -default-features = false diff --git a/core/src/errors/core_circuit.rs b/core/src/errors/core_circuit.rs deleted file mode 100644 index eaeea07595..0000000000 --- a/core/src/errors/core_circuit.rs +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (C) 2019-2021 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::Value; -use leo_ast::{Error as FormattedError, Span}; - -use snarkvm_errors::gadgets::SynthesisError; - -use std::path::Path; - -#[derive(Debug, Error, Eq, PartialEq)] -pub enum CoreCircuitError { - #[error("{}", _0)] - Error(#[from] FormattedError), -} - -impl CoreCircuitError { - pub fn set_path(&mut self, path: &Path) { - match self { - CoreCircuitError::Error(error) => error.set_path(path), - } - } - - fn new_from_span(message: String, span: Span) -> Self { - CoreCircuitError::Error(FormattedError::new_from_span(message, span)) - } - - pub fn arguments_length(expected: usize, actual: usize, span: Span) -> Self { - let message = format!("Core circuit expected {} arguments, found {}", expected, actual); - - CoreCircuitError::new_from_span(message, span) - } - - pub fn array_length(expected: usize, actual: usize, span: Span) -> Self { - let message = format!( - "Core circuit expected an array of length {}, found an array of length {}", - expected, actual - ); - - CoreCircuitError::new_from_span(message, span) - } - - pub fn cannot_enforce(operation: String, error: SynthesisError, span: Span) -> Self { - let message = format!( - "The gadget operation `{}` failed due to synthesis error `{:?}`", - operation, error, - ); - - Self::new_from_span(message, span) - } - - pub fn invalid_array(actual: Value, span: Span) -> Self { - let message = format!("Core circuit expected an array argument, found `{}`", actual); - - Self::new_from_span(message, span) - } - - pub fn invalid_array_bytes(actual: Value, span: Span) -> Self { - let message = format!( - "Core circuit expected an array of UInt8 gadgets, found an array of `{}`", - actual - ); - - Self::new_from_span(message, span) - } -} diff --git a/core/src/errors/core_package.rs b/core/src/errors/core_package.rs deleted file mode 100644 index 9242435802..0000000000 --- a/core/src/errors/core_package.rs +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (C) 2019-2021 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 leo_ast::{Error as FormattedError, Span}; - -use std::path::Path; - -#[derive(Debug, Error)] -pub enum CorePackageError { - #[error("{}", _0)] - Error(#[from] FormattedError), -} - -impl CorePackageError { - pub fn set_path(&mut self, path: &Path) { - match self { - CorePackageError::Error(error) => error.set_path(path), - } - } - - fn new_from_span(message: String, span: Span) -> Self { - CorePackageError::Error(FormattedError::new_from_span(message, span)) - } - - pub fn core_package_star(span: Span) -> Self { - let message = "Cannot import star from leo-core".to_string(); - - Self::new_from_span(message, span) - } - - pub fn undefined_core_circuit(name: String, span: Span) -> Self { - let message = format!("Core circuit `{}` not found in leo-core", name); - - Self::new_from_span(message, span) - } - - pub fn undefined_unstable_core_circuit(name: String, span: Span) -> Self { - let message = format!("Unstable core circuit `{}` not found in leo-core", name); - - Self::new_from_span(message, span) - } -} diff --git a/core/src/errors/core_package_list.rs b/core/src/errors/core_package_list.rs deleted file mode 100644 index b5c1eaec04..0000000000 --- a/core/src/errors/core_package_list.rs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (C) 2019-2021 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 leo_ast::{Error as FormattedError, ImportSymbol, Span}; - -use crate::CorePackageError; -use std::path::Path; - -#[derive(Debug, Error)] -pub enum CorePackageListError { - #[error("{}", _0)] - CorePackageError(#[from] CorePackageError), - - #[error("{}", _0)] - Error(#[from] FormattedError), -} - -impl CorePackageListError { - pub fn set_path(&mut self, path: &Path) { - match self { - CorePackageListError::CorePackageError(error) => error.set_path(path), - CorePackageListError::Error(error) => error.set_path(path), - } - } - - fn new_from_span(message: String, span: Span) -> Self { - CorePackageListError::Error(FormattedError::new_from_span(message, span)) - } - - pub fn invalid_core_package(symbol: ImportSymbol) -> Self { - let message = format!("No package `{}` in leo-core", symbol); - let span = symbol.span; - - Self::new_from_span(message, span) - } - - pub fn core_package_star(span: Span) -> Self { - let message = "Cannot import star from leo-core".to_string(); - - Self::new_from_span(message, span) - } -} diff --git a/core/src/errors/leo_core_package.rs b/core/src/errors/leo_core_package.rs deleted file mode 100644 index fbf549d586..0000000000 --- a/core/src/errors/leo_core_package.rs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (C) 2019-2021 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::{CoreCircuitError, CorePackageListError}; -use leo_ast::{Error as FormattedError, Span}; - -use std::path::Path; - -#[derive(Debug, Error)] -pub enum LeoCorePackageError { - #[error("{}", _0)] - CoreCircuitError(#[from] CoreCircuitError), - - #[error("{}", _0)] - CorePackageListError(#[from] CorePackageListError), - - #[error("{}", _0)] - Error(#[from] FormattedError), -} - -impl LeoCorePackageError { - pub fn set_path(&mut self, path: &Path) { - match self { - LeoCorePackageError::CoreCircuitError(error) => error.set_path(path), - LeoCorePackageError::CorePackageListError(error) => error.set_path(path), - LeoCorePackageError::Error(error) => error.set_path(path), - } - } - - fn new_from_span(message: String, span: Span) -> Self { - LeoCorePackageError::Error(FormattedError::new_from_span(message, span)) - } - - pub fn undefined_core_circuit(circuit_name: String, span: Span) -> Self { - let message = format!("Core circuit `{}` not found in `leo-core`", circuit_name); - - Self::new_from_span(message, span) - } -} diff --git a/core/src/errors/mod.rs b/core/src/errors/mod.rs deleted file mode 100644 index 74cab0d9a9..0000000000 --- a/core/src/errors/mod.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (C) 2019-2021 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 . - -pub mod core_circuit; -pub use self::core_circuit::*; - -pub mod core_package; -pub use self::core_package::*; - -pub mod core_package_list; -pub use self::core_package_list::*; - -pub mod leo_core_package; -pub use self::leo_core_package::*; diff --git a/core/src/lib.rs b/core/src/lib.rs deleted file mode 100644 index a7aa49dd37..0000000000 --- a/core/src/lib.rs +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (C) 2019-2021 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 . - -#[macro_use] -extern crate thiserror; - -pub mod packages; -pub use self::packages::*; - -pub mod errors; -pub use self::errors::*; - -pub mod types; -pub use self::types::*; - -use crate::CoreCircuit; -use leo_ast::Span; - -use snarkvm_models::{ - curves::{Field, PrimeField}, - gadgets::r1cs::ConstraintSystem, -}; - -/// Calls a core circuit by it's given name. -/// This function should be called by the compiler when enforcing a core circuit function expression. -pub fn call_core_circuit>( - cs: CS, - circuit_name: String, - arguments: Vec, - span: Span, -) -> Result, LeoCorePackageError> { - // Match core circuit name - Ok(match circuit_name.as_str() { - CORE_UNSTABLE_BLAKE2S_NAME => Blake2sCircuit::call(cs, arguments, span)?, - _ => return Err(LeoCorePackageError::undefined_core_circuit(circuit_name, span)), - }) -} diff --git a/core/src/packages/mod.rs b/core/src/packages/mod.rs deleted file mode 100644 index d701791565..0000000000 --- a/core/src/packages/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (C) 2019-2021 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 . - -pub mod unstable; -pub use self::unstable::*; diff --git a/core/src/packages/unstable/blake2s.rs b/core/src/packages/unstable/blake2s.rs deleted file mode 100644 index 71873daf98..0000000000 --- a/core/src/packages/unstable/blake2s.rs +++ /dev/null @@ -1,291 +0,0 @@ -// Copyright (C) 2019-2021 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::{CoreCircuit, CoreCircuitError, Value}; - -use leo_ast::{ - ArrayDimensions, - Block, - CallExpression, - Circuit, - CircuitMember, - Expression, - Function, - FunctionInput, - FunctionInputVariable, - Identifier, - IntegerType, - PositiveNumber, - ReturnStatement, - Span, - Statement, - Type, -}; -use snarkvm_gadgets::algorithms::prf::Blake2sGadget; -use snarkvm_models::{ - curves::{Field, PrimeField}, - gadgets::{ - algorithms::PRFGadget, - r1cs::ConstraintSystem, - utilities::{uint::UInt8, ToBytesGadget}, - }, -}; - -// internal identifier -pub const CORE_UNSTABLE_BLAKE2S_NAME: &str = "#blake2s"; -pub const CORE_UNSTABLE_BLAKE2S_PACKAGE_NAME: &str = "Blake2s"; - -#[derive(Clone, PartialEq, Eq)] -pub struct Blake2sCircuit {} - -impl CoreCircuit for Blake2sCircuit { - fn name() -> String { - CORE_UNSTABLE_BLAKE2S_NAME.to_owned() - } - - /* Blake2s circuit ast - * circuit Blake2s { - * static function hash(seed: [u8; 32], message: [u8; 32]) -> [u8; 32] { - * // call `check_eval_gadget` in snarkOS - * return check_eval_gadget(seed, message) - * } - */ - fn ast(circuit_name: Identifier, span: Span) -> Circuit { - Circuit { - circuit_name, - members: vec![CircuitMember::CircuitFunction(Function { - identifier: Identifier { - name: "hash".to_owned(), - span: span.clone(), - }, - input: vec![ - FunctionInput::Variable(FunctionInputVariable { - identifier: Identifier { - name: "seed".to_owned(), - span: span.clone(), - }, - mutable: false, - type_: Type::Array( - Box::new(Type::IntegerType(IntegerType::U8)), - ArrayDimensions(vec![PositiveNumber { - value: 32usize.to_string(), - }]), - ), - span: span.clone(), - }), - FunctionInput::Variable(FunctionInputVariable { - identifier: Identifier { - name: "message".to_owned(), - span: span.clone(), - }, - mutable: false, - type_: Type::Array( - Box::new(Type::IntegerType(IntegerType::U8)), - ArrayDimensions(vec![PositiveNumber { - value: 32usize.to_string(), - }]), - ), - span: span.clone(), - }), - ], - output: Some(Type::Array( - Box::new(Type::IntegerType(IntegerType::U8)), - ArrayDimensions(vec![PositiveNumber { - value: 32usize.to_string(), - }]), - )), - block: Block { - statements: vec![Statement::Return(ReturnStatement { - expression: Expression::Call(CallExpression { - function: Box::new(Expression::Identifier(Identifier::new_with_span(&Self::name(), &span))), - arguments: vec![ - Expression::Identifier(Identifier::new_with_span("seed", &span)), - Expression::Identifier(Identifier::new_with_span("message", &span)), - ], - span: span.clone(), - }), - span: span.clone(), - })], - span: span.clone(), - }, - span, - })], - } - } - - /// Calls the native `Blake2sGadget` on the given constraint system with the given arguments - fn call>( - mut cs: CS, - arguments: Vec, - span: Span, - ) -> Result, CoreCircuitError> { - // The blake2s check evaluation gadget has two arguments: seed and input - let expected_length = 2usize; - let actual_length = arguments.len(); - - if expected_length != actual_length { - return Err(CoreCircuitError::arguments_length(expected_length, actual_length, span)); - } - - let seed_value = arguments[0].to_owned(); - let input_value = arguments[1].to_owned(); - - let seed = check_array_bytes(seed_value, 32, span.clone())?; - let input = check_array_bytes(input_value, 32, span.clone())?; - - // Call blake2s gadget - let digest = - Blake2sGadget::check_evaluation_gadget(cs.ns(|| "blake2s hash"), &seed[..], &input[..]).map_err(|e| { - CoreCircuitError::cannot_enforce("Blake2s check evaluation gadget".to_owned(), e, span.clone()) - })?; - - // Convert digest to bytes - let bytes = digest - .to_bytes(cs) - .map_err(|e| CoreCircuitError::cannot_enforce("Vec ToBytes".to_owned(), e, span.clone()))?; - - let return_value = bytes.into_iter().map(Value::U8).collect(); - - // Return one array digest value - Ok(vec![Value::Array(return_value)]) - } -} - -fn check_array_bytes(value: Value, size: usize, span: Span) -> Result, CoreCircuitError> { - let array_value = match value { - Value::Array(array) => array, - value => return Err(CoreCircuitError::invalid_array(value, span)), - }; - - if size != array_value.len() { - return Err(CoreCircuitError::array_length(size, array_value.len(), span)); - } - - let mut array_bytes = Vec::with_capacity(array_value.len()); - - for value in array_value { - let byte = match value { - Value::U8(u8) => u8, - value => return Err(CoreCircuitError::invalid_array_bytes(value, span)), - }; - - array_bytes.push(byte) - } - - Ok(array_bytes) -} - -#[cfg(test)] -mod tests { - use super::*; - use snarkvm_curves::bls12_377::Fr; - use snarkvm_models::gadgets::{ - r1cs::TestConstraintSystem, - utilities::{boolean::Boolean, uint::UInt8}, - }; - - #[test] - fn test_call_arguments_length_fail() { - let cs = TestConstraintSystem::::new(); - - let seed = Value::Array(vec![]); - let dummy_span = Span { - text: "".to_string(), - line: 0, - start: 0, - end: 0, - }; - - let err = Blake2sCircuit::call(cs, vec![seed], dummy_span.clone()).err(); - - assert!(err.is_some()); - - let expected = CoreCircuitError::arguments_length(2, 1, dummy_span); - let actual = err.unwrap(); - - assert_eq!(expected, actual); - } - - #[test] - fn test_array_length_fail() { - let cs = TestConstraintSystem::::new(); - - let seed = Value::Array(vec![]); - let input = Value::Array(vec![]); - let dummy_span = Span { - text: "".to_string(), - line: 0, - start: 0, - end: 0, - }; - - let err = Blake2sCircuit::call(cs, vec![seed, input], dummy_span.clone()).err(); - - assert!(err.is_some()); - - let expected = CoreCircuitError::array_length(32, 0, dummy_span); - let actual = err.unwrap(); - - assert_eq!(expected, actual); - } - - #[test] - fn test_invalid_array() { - let cs = TestConstraintSystem::::new(); - - let seed = Value::U8(UInt8::constant(0)); - let input = Value::Array(vec![]); - let dummy_span = Span { - text: "".to_string(), - line: 0, - start: 0, - end: 0, - }; - - let err = Blake2sCircuit::call(cs, vec![seed.clone(), input], dummy_span.clone()).err(); - - assert!(err.is_some()); - - let expected = CoreCircuitError::invalid_array(seed, dummy_span); - let actual = err.unwrap(); - - assert_eq!(expected, actual); - } - - #[test] - fn test_invalid_array_bytes() { - let cs = TestConstraintSystem::::new(); - - let invalid_byte = Value::Boolean(Boolean::Constant(true)); - let seed = Value::Array(vec![invalid_byte.clone(); 32]); - let input = Value::Array(vec![Value::U8(UInt8::constant(0)); 32]); - let dummy_span = Span { - text: "".to_string(), - line: 0, - start: 0, - end: 0, - }; - - let err = Blake2sCircuit::call(cs, vec![seed, input], dummy_span.clone()).err(); - - assert!(err.is_some()); - - let expected = CoreCircuitError::invalid_array_bytes(invalid_byte, dummy_span); - let actual = err.unwrap(); - - assert_eq!(expected, actual); - } -} diff --git a/core/src/types/core_circuit_struct_list.rs b/core/src/types/core_circuit_struct_list.rs deleted file mode 100644 index 58a54a322e..0000000000 --- a/core/src/types/core_circuit_struct_list.rs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (C) 2019-2021 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 leo_ast::Circuit; - -/// List of imported core circuit structs. -/// This struct is created from a `CorePackageList` -pub struct CoreCircuitStructList { - /// [(circuit_name, circuit_struct)] - symbols: Vec<(String, Circuit)>, -} - -impl CoreCircuitStructList { - pub(crate) fn new() -> Self { - Self { symbols: vec![] } - } - - pub(crate) fn push(&mut self, name: String, circuit: Circuit) { - self.symbols.push((name, circuit)) - } - - pub fn symbols(&self) -> impl Iterator { - self.symbols.iter() - } -} diff --git a/core/src/types/core_package.rs b/core/src/types/core_package.rs deleted file mode 100644 index f4d97a1cee..0000000000 --- a/core/src/types/core_package.rs +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (C) 2019-2021 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::{ - unstable::blake2s::{Blake2sCircuit, CORE_UNSTABLE_BLAKE2S_NAME}, - CoreCircuit, - CoreCircuitStructList, - CorePackageError, -}; -use leo_ast::{Identifier, ImportSymbol, Package, PackageAccess}; -use std::convert::TryFrom; - -/// A core package dependency to be imported into a Leo program. -/// Each `CorePackage` contains one or more `CoreCircuit`s that can be accessed by name. -#[derive(Debug, Clone)] -pub struct CorePackage { - name: Identifier, - unstable: bool, - circuits: Vec, -} - -impl CorePackage { - pub(crate) fn new(name: Identifier) -> Self { - Self { - name, - unstable: false, - circuits: vec![], - } - } - - // Set the `unstable` flag to true if we are importing an unstable core package - pub(crate) fn set_unstable(&mut self) { - self.unstable = true; - } - - // Stores all `CoreCircuit` names that are being accessed in the current `CorePackage` - fn get_circuit_names(&mut self, access: PackageAccess) -> Result<(), CorePackageError> { - match access { - PackageAccess::SubPackage(package) => return self.get_circuit_names(package.access), - PackageAccess::Star(span) => return Err(CorePackageError::core_package_star(span)), - PackageAccess::Multiple(accesses) => { - for access in accesses { - self.get_circuit_names(access)?; - } - } - PackageAccess::Symbol(symbol) => self.circuits.push(symbol), - } - Ok(()) - } - - fn circuit_name_to_ast_name(circuit_name: &str) -> Option { - let first_character = &circuit_name[..1]; - let remaining_characters = &circuit_name[1..]; - if first_character.to_uppercase() != first_character - || remaining_characters != remaining_characters.to_lowercase() - { - return None; - } - Some(format!("#{}", circuit_name.to_lowercase())) - } - - // Stores all `CoreCircuit` structs that are being accessed in the current `CorePackage` - pub(crate) fn get_circuit_structs( - &self, - circuit_structs: &mut CoreCircuitStructList, - ) -> Result<(), CorePackageError> { - for circuit in &self.circuits { - let circuit_name = circuit.symbol.name.as_str(); - let span = circuit.span.clone(); - - // take the alias if it is present - let id = circuit.alias.clone().unwrap_or_else(|| circuit.symbol.clone()); - let name = id.name.clone(); - - let circuit = if self.unstable { - // match unstable core circuit - match &*Self::circuit_name_to_ast_name(circuit_name).unwrap_or_default() { - CORE_UNSTABLE_BLAKE2S_NAME => Blake2sCircuit::ast(circuit.symbol.clone(), span), - name => { - return Err(CorePackageError::undefined_unstable_core_circuit( - name.to_string(), - span, - )); - } - } - } else { - // match core circuit - return Err(CorePackageError::undefined_core_circuit(circuit_name.to_string(), span)); - }; - - circuit_structs.push(name, circuit) - } - - Ok(()) - } -} - -impl TryFrom for CorePackage { - type Error = CorePackageError; - - fn try_from(package: Package) -> Result { - // Create new core package - let mut core_package = Self::new(package.name); - - // Fetch all circuit symbols imported from core package - core_package.get_circuit_names(package.access)?; - - Ok(core_package) - } -} diff --git a/core/src/types/core_package_list.rs b/core/src/types/core_package_list.rs deleted file mode 100644 index 5ec7d5cfea..0000000000 --- a/core/src/types/core_package_list.rs +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (C) 2019-2021 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::{CoreCircuitStructList, CorePackage, CorePackageListError, UNSTABLE_CORE_PACKAGE_KEYWORD}; -use leo_ast::PackageAccess; -use std::convert::TryFrom; - -/// A list of core package dependencies. -/// This struct is created when the compiler parses a core import statement. -#[derive(Debug)] -pub struct CorePackageList { - packages: Vec, -} - -impl CorePackageList { - pub(crate) fn new() -> Self { - Self { packages: vec![] } - } - - pub(crate) fn push(&mut self, package: CorePackage) { - self.packages.push(package); - } - - // Parse all dependencies after `import core.` - pub fn from_package_access(access: PackageAccess) -> Result { - let mut new = Self::new(); - - package_access_helper(&mut new, access, false)?; - - Ok(new) - } - - // Return a list of all symbols that need to be stored in the current function - pub fn to_symbols(&self) -> Result { - let mut symbols = CoreCircuitStructList::new(); - - for package in &self.packages { - package.get_circuit_structs(&mut symbols)?; - } - - Ok(symbols) - } -} - -fn package_access_helper( - list: &mut CorePackageList, - access: PackageAccess, - is_unstable: bool, -) -> Result<(), CorePackageListError> { - match access { - PackageAccess::Symbol(symbol) => return Err(CorePackageListError::invalid_core_package(symbol)), - PackageAccess::Multiple(core_functions) => { - for access in core_functions { - package_access_helper(list, access, is_unstable)?; - } - } - PackageAccess::SubPackage(package) => { - // Set the `unstable` flag to true if we are importing an unstable core package - if package.name.name.eq(UNSTABLE_CORE_PACKAGE_KEYWORD) { - package_access_helper(list, package.access, true)?; - } else { - let mut core_package = CorePackage::try_from(*package)?; - - if is_unstable { - core_package.set_unstable() - } - - list.push(core_package); - } - } - PackageAccess::Star(span) => return Err(CorePackageListError::core_package_star(span)), - } - - Ok(()) -} diff --git a/core/src/types/mod.rs b/core/src/types/mod.rs deleted file mode 100644 index 5f875ed0ac..0000000000 --- a/core/src/types/mod.rs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (C) 2019-2021 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 . - -pub mod core_circuit; -pub use self::core_circuit::*; - -pub mod core_circuit_struct_list; -pub use self::core_circuit_struct_list::*; - -pub mod core_package; -pub use self::core_package::*; - -pub mod core_package_list; -pub use self::core_package_list::*; - -pub mod value; -pub use self::value::*; - -pub static UNSTABLE_CORE_PACKAGE_KEYWORD: &str = "unstable"; diff --git a/core/src/types/value.rs b/core/src/types/value.rs deleted file mode 100644 index 05edeac2b5..0000000000 --- a/core/src/types/value.rs +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (C) 2019-2021 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 leo_gadgets::signed_integer::*; - -use snarkvm_models::gadgets::utilities::{boolean::Boolean, uint::*}; -use std::fmt; - -/// An intermediate value format that can be converted into a `ConstrainedValue` for the compiler -/// TODO(collinc97): implement other constrained values -#[derive(Clone)] -pub enum Value { - Boolean(Boolean), - - U8(UInt8), - U16(UInt16), - U32(UInt32), - U64(UInt64), - U128(UInt128), - - I8(Int8), - I16(Int16), - I32(Int32), - I64(Int64), - I128(Int128), - - Array(Vec), - Tuple(Vec), -} - -impl fmt::Display for Value { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let string_option = match self { - Value::Boolean(value) => value.get_value().map(|v| v.to_string()), - Value::U8(value) => value.value.map(|v| v.to_string()), - Value::U16(value) => value.value.map(|v| v.to_string()), - Value::U32(value) => value.value.map(|v| v.to_string()), - Value::U64(value) => value.value.map(|v| v.to_string()), - Value::U128(value) => value.value.map(|v| v.to_string()), - Value::I8(value) => value.value.map(|v| v.to_string()), - Value::I16(value) => value.value.map(|v| v.to_string()), - Value::I32(value) => value.value.map(|v| v.to_string()), - Value::I64(value) => value.value.map(|v| v.to_string()), - Value::I128(value) => value.value.map(|v| v.to_string()), - Value::Array(values) => { - let string = values.iter().map(|v| v.to_string()).collect::>().join(", "); - - write!(f, "[{}]", string)?; - - Some("".to_owned()) - } - Value::Tuple(values) => { - let string = values.iter().map(|v| v.to_string()).collect::>().join(", "); - - write!(f, "[{}]", string)?; - - Some("".to_owned()) - } - }; - - let string = string_option.unwrap_or_else(|| "[input]".to_owned()); - - write!(f, "{}", string) - } -} diff --git a/imports/Cargo.toml b/imports/Cargo.toml index 27ee9d963a..c216830dcc 100644 --- a/imports/Cargo.toml +++ b/imports/Cargo.toml @@ -25,6 +25,10 @@ version = "1.0.8" path = "../grammar" version = "1.0.8" +[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 ac24897ca8..f3d901560c 100644 --- a/imports/src/errors/import_parser.rs +++ b/imports/src/errors/import_parser.rs @@ -13,7 +13,8 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use leo_ast::{DeprecatedError, Error as FormattedError, Identifier, Span}; +use leo_asg::AsgConvertError; +use leo_ast::{AstError, DeprecatedError, Error as FormattedError, Identifier, Span}; use leo_grammar::ParserError; use std::{io, path::Path}; @@ -28,6 +29,19 @@ 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::DeprecatedError(x) => AsgConvertError::AstError(AstError::DeprecatedError(x)), + ImportParserError::AsgConvertError(x) => x, + } + } } impl ImportParserError { @@ -48,6 +62,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 33189bb564..0000000000 --- a/imports/src/parser/core_package.rs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (C) 2019-2021 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 73408f43ef..2e4de8180a 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::{AsgConvertError, ImportResolver, Program, Span}; use indexmap::{IndexMap, IndexSet}; use std::env::current_dir; @@ -26,74 +26,30 @@ 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()); + } + if let Some(program) = self.imports.get(&full_path) { + return Ok(Some(program.clone())); } - - // 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(); + let path = + current_dir().map_err(|x| -> AsgConvertError { ImportParserError::current_directory_error(x).into() })?; - // 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)?; - } - - Ok(imports) + self.partial_imports.insert(full_path.clone()); + let program = imports + .parse_package(path, 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)) } } diff --git a/imports/src/parser/mod.rs b/imports/src/parser/mod.rs index 2d5a8a5456..d278f2a40f 100644 --- a/imports/src/parser/mod.rs +++ b/imports/src/parser/mod.rs @@ -15,9 +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 40123bdd46..6a1dd68e0a 100644 --- a/imports/src/parser/parse_package.rs +++ b/imports/src/parser/parse_package.rs @@ -14,8 +14,8 @@ // 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}; @@ -24,30 +24,19 @@ 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( + 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(()) - } + remaining_segments: &[&str], + span: &Span, + ) -> Result { + if !remaining_segments.is_empty() { + 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 +44,20 @@ 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 +79,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 +90,42 @@ 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 a6f1419b72..0b0a5b2c7d 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 + .map_err(|_| ImportParserError::convert_os_string(span.clone()))?; - // Attempt to insert the Leo syntax tree for the imported package. - self.insert_import(file_name, program); + let mut file_path = package.path(); + if file_type.is_dir() { + file_path.push(LIBRARY_FILE); - Ok(()) + 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())?) } } diff --git a/symbol-table/Cargo.toml b/symbol-table/Cargo.toml deleted file mode 100644 index 04eb96e7ff..0000000000 --- a/symbol-table/Cargo.toml +++ /dev/null @@ -1,44 +0,0 @@ -[package] -name = "leo-symbol-table" -version = "1.0.8" -authors = [ "The Aleo Team " ] -description = "Stores user-defined variables during type resolution" -homepage = "https://aleo.org" -repository = "https://github.com/AleoHQ/leo" -keywords = [ - "aleo", - "cryptography", - "leo", - "programming-language", - "zero-knowledge" -] -categories = [ "cryptography::cryptocurrencies", "web-programming" ] -include = [ "Cargo.toml", "src", "README.md", "LICENSE.md" ] -license = "GPL-3.0" -edition = "2018" - -[dependencies.leo-ast] -path = "../ast" -version = "1.0.8" - -[dependencies.leo-core] -path = "../core" -version = "1.0.8" - -[dependencies.leo-grammar] -path = "../grammar" -version = "1.0.8" - -[dependencies.leo-imports] -path = "../imports" -version = "1.0.8" - -[dependencies.indexmap] -version = "1.6.1" -features = [ "serde-1" ] - -[dependencies.serde] -version = "1.0" - -[dependencies.thiserror] -version = "1.0" diff --git a/symbol-table/src/attributes/attribute.rs b/symbol-table/src/attributes/attribute.rs deleted file mode 100644 index 92aa399110..0000000000 --- a/symbol-table/src/attributes/attribute.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (C) 2019-2021 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 serde::{Deserialize, Serialize}; - -/// Indicates that a program variable has additional functionality. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub enum Attribute { - Mutable, - Static, -} diff --git a/symbol-table/src/attributes/mod.rs b/symbol-table/src/attributes/mod.rs deleted file mode 100644 index 5889dbbc6d..0000000000 --- a/symbol-table/src/attributes/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (C) 2019-2021 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 . - -pub mod attribute; -pub use self::attribute::*; diff --git a/symbol-table/src/errors/mod.rs b/symbol-table/src/errors/mod.rs deleted file mode 100644 index 5a78a435c9..0000000000 --- a/symbol-table/src/errors/mod.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (C) 2019-2021 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 . - -pub mod symbol_table; -pub use self::symbol_table::*; - -pub mod type_; -pub use self::type_::*; diff --git a/symbol-table/src/errors/symbol_table.rs b/symbol-table/src/errors/symbol_table.rs deleted file mode 100644 index 07bfa9b00d..0000000000 --- a/symbol-table/src/errors/symbol_table.rs +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (C) 2019-2021 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::{TypeError, UserDefinedType}; -use leo_ast::{Error as FormattedError, ImportSymbol, Program, Span}; -use leo_core::{CorePackageListError, LeoCorePackageError}; - -use std::path::Path; - -/// Errors encountered when tracking variable, function, and circuit names in a program. -#[derive(Debug, Error)] -pub enum SymbolTableError { - #[error("{}", _0)] - CorePackageListError(#[from] CorePackageListError), - - #[error("{}", _0)] - Error(#[from] FormattedError), - - #[error("{}", _0)] - LeoCorePackageError(#[from] LeoCorePackageError), - - #[error("{}", _0)] - TypeError(#[from] TypeError), -} - -impl SymbolTableError { - /// - /// Sets the filepath for the error stacktrace. - /// - pub fn set_path(&mut self, path: &Path) { - match self { - SymbolTableError::CorePackageListError(error) => error.set_path(path), - SymbolTableError::Error(error) => error.set_path(path), - SymbolTableError::LeoCorePackageError(error) => error.set_path(path), - SymbolTableError::TypeError(error) => error.set_path(path), - } - } - - /// - /// Returns a new formatted error with a given message and span information. - /// - fn new_from_span(message: String, span: Span) -> Self { - SymbolTableError::Error(FormattedError::new_from_span(message, span)) - } - - /// - /// Two circuits have been defined with the same name. - /// - pub fn duplicate_circuit(variable: UserDefinedType) -> Self { - let message = format!("Duplicate circuit definition found for `{}`", variable.identifier); - - Self::new_from_span(message, variable.identifier.span) - } - - /// - /// Two functions have been defined with the same name. - /// - pub fn duplicate_function(variable: UserDefinedType) -> Self { - let message = format!("Duplicate function definition found for `{}`", variable.identifier); - - Self::new_from_span(message, variable.identifier.span) - } - - /// - /// Attempted to access a package name that is not defined. - /// - pub fn unknown_package(name: &str, span: &Span) -> Self { - let message = format!( - "Cannot find imported package `{}` in source files or import directory", - name - ); - - Self::new_from_span(message, span.to_owned()) - } - - /// - /// Attempted to import a name that is not defined in the current file. - /// - pub fn unknown_symbol(symbol: &ImportSymbol, program: &Program) -> Self { - let message = format!( - "Cannot find imported symbol `{}` in imported file `{}`", - symbol.symbol, program.name - ); - - Self::new_from_span(message, symbol.span.to_owned()) - } -} diff --git a/symbol-table/src/errors/type_.rs b/symbol-table/src/errors/type_.rs deleted file mode 100644 index b89f3c7a35..0000000000 --- a/symbol-table/src/errors/type_.rs +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (C) 2019-2021 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 leo_ast::{Error as FormattedError, Identifier, Span}; - -use std::path::Path; - -/// Errors encountered when resolving types. -#[derive(Debug, Error)] -pub enum TypeError { - #[error("{}", _0)] - Error(#[from] FormattedError), -} - -impl TypeError { - /// - /// Set the filepath for the error stacktrace. - /// - pub fn set_path(&mut self, path: &Path) { - match self { - TypeError::Error(error) => error.set_path(path), - } - } - - /// - /// Return a new formatted error with a given message and span information. - /// - fn new_from_span(message: String, span: Span) -> Self { - TypeError::Error(FormattedError::new_from_span(message, span)) - } - - /// - /// The `Self` keyword was used outside of a circuit. - /// - pub fn self_not_available(span: Span) -> Self { - let message = "Type `Self` is only available in circuit definitions and circuit functions.".to_string(); - - Self::new_from_span(message, span) - } - - /// - /// Found an unknown circuit name. - /// - pub fn undefined_circuit(identifier: Identifier) -> Self { - let message = format!( - "Type circuit `{}` must be defined before it is used in an expression.", - identifier.name - ); - - Self::new_from_span(message, identifier.span) - } - - /// - /// Found an unknown circuit member name. - /// - pub fn undefined_circuit_member(identifier: Identifier) -> Self { - let message = format!("Circuit has no member `{}`.", identifier.name); - - Self::new_from_span(message, identifier.span) - } - - /// - /// Found an unknown function name. - /// - pub fn undefined_function(identifier: Identifier) -> Self { - let message = format!( - "Type function `{}` must be defined before it is used in an expression.", - identifier.name - ); - - Self::new_from_span(message, identifier.span) - } -} diff --git a/symbol-table/src/imports/imported_symbols.rs b/symbol-table/src/imports/imported_symbols.rs deleted file mode 100644 index f7444874e8..0000000000 --- a/symbol-table/src/imports/imported_symbols.rs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (C) 2019-2021 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 leo_ast::{ImportStatement, ImportSymbol, Package, PackageAccess}; - -/// Stores the the package file name and imported symbol from an import statement -#[derive(Debug)] -pub struct ImportedSymbols { - pub symbols: Vec<(String, ImportSymbol)>, -} - -impl ImportedSymbols { - pub fn new(import: &ImportStatement) -> Self { - let mut imported_symbols = Self::default(); - - imported_symbols.push_package(&import.package); - - imported_symbols - } - - fn push_package(&mut self, package: &Package) { - self.push_package_access(package.name.name.clone(), &package.access); - } - - fn push_package_access(&mut self, package: String, access: &PackageAccess) { - match access { - PackageAccess::SubPackage(package) => self.push_package(package), - PackageAccess::Star(span) => { - let star = ImportSymbol::star(span); - self.symbols.push((package, star)); - } - PackageAccess::Symbol(symbol) => self.symbols.push((package, symbol.clone())), - PackageAccess::Multiple(packages) => packages - .iter() - .for_each(|access| self.push_package_access(package.clone(), access)), - } - } -} - -impl Default for ImportedSymbols { - fn default() -> Self { - Self { symbols: Vec::new() } - } -} diff --git a/symbol-table/src/imports/mod.rs b/symbol-table/src/imports/mod.rs deleted file mode 100644 index 73983a5fe8..0000000000 --- a/symbol-table/src/imports/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (C) 2019-2021 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 . - -pub mod imported_symbols; -pub use self::imported_symbols::*; diff --git a/symbol-table/src/lib.rs b/symbol-table/src/lib.rs deleted file mode 100644 index 9e124dbe37..0000000000 --- a/symbol-table/src/lib.rs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (C) 2019-2021 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 symbol table for a Leo program. -//! -//! This module contains the [`SymbolTable`] type, an abstract data type that tracks the current -//! bindings for functions and circuits in a Leo program. -//! -//! A new [`Symbol Table`] type can be created from a reference to a [`LeoAst`]. -//! A [`Symbol Table`] type can be used to create a new [`TypeInference`] type. - -#[macro_use] -extern crate thiserror; - -pub mod attributes; -pub use self::attributes::*; - -pub mod errors; -pub use self::errors::*; - -pub mod imports; -pub use self::imports::*; - -pub mod symbol_table; -pub use self::symbol_table::*; - -pub mod types; -pub use self::types::*; diff --git a/symbol-table/src/symbol_table.rs b/symbol-table/src/symbol_table.rs deleted file mode 100644 index 87ccd8b953..0000000000 --- a/symbol-table/src/symbol_table.rs +++ /dev/null @@ -1,525 +0,0 @@ -// Copyright (C) 2019-2021 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::{CircuitType, CircuitVariableType, FunctionType, ImportedSymbols, SymbolTableError, UserDefinedType}; -use leo_ast::{Circuit, Function, Identifier, ImportStatement, ImportSymbol, Input, Package, Program}; -use leo_core::CorePackageList; -use leo_imports::ImportParser; - -use indexmap::{IndexMap, IndexSet}; - -pub const INPUT_VARIABLE_NAME: &str = "input"; -pub const RECORD_VARIABLE_NAME: &str = "record"; -pub const REGISTERS_VARIABLE_NAME: &str = "registers"; -pub const STATE_VARIABLE_NAME: &str = "state"; -pub const STATE_LEAF_VARIABLE_NAME: &str = "state_leaf"; - -/// The symbol table for a Leo program. -/// -/// A symbol table has access to all function and circuit names in its parent's symbol table. -/// A symbol table cannot access names in its child's symbol table. -/// A child symbol table cannot access names in another sibling's symbol table. -#[derive(Clone, Default)] -pub struct SymbolTable { - /// Maps name -> parameter type. - names: IndexMap, - - /// Maps circuit name -> circuit type. - pub circuits: IndexMap, - - /// Maps function name -> function type. - pub functions: IndexMap, - - /// The parent of this symbol table. - parent: Option>, -} - -impl SymbolTable { - /// - /// Returns a new `SymbolTable` from a given, program, imported programs, and program input. - /// - /// Checks that each circuit or function name is unique. - /// Unique names are added to a table of name -> user defined type. - /// - /// Checks that each circuit or function definition contains valid types. - /// - pub fn new( - program: &Program, - import_parser: &ImportParser, - input: &Input, - ) -> Result { - // Create a new symbol table. - let mut table = Self::default(); - - // Insert input types into symbol table. - table.insert_input(input)?; - - // Check for duplicate program and import names. - table.check_names(program, import_parser, input)?; - - // Check for unknown or invalid types. - table.check_types(program)?; - - Ok(table) - } - - /// - /// Insert a function or circuit name into the symbol table from a given name and variable type. - /// - /// If the symbol table did not have this name present, `None` is returned. - /// If the symbol table did have this name present, the variable type is updated, and the old - /// variable type is returned. - /// - pub fn insert_name(&mut self, name: String, variable_type: UserDefinedType) -> Option { - self.names.insert(name, variable_type) - } - - /// - /// Insert a circuit name into the symbol table from a given name and variable type. - /// - /// Returns an error if the circuit name is a duplicate. - /// - pub fn insert_circuit_name( - &mut self, - name: String, - variable_type: UserDefinedType, - ) -> Result<(), SymbolTableError> { - // Check that the circuit name is unique. - match self.insert_name(name, variable_type) { - Some(duplicate) => Err(SymbolTableError::duplicate_circuit(duplicate)), - None => Ok(()), - } - } - - /// - /// Insert a function name into the symbol table from a given name and variable type. - /// - /// Returns an error if the function name is a duplicate. - /// - pub fn insert_function_name( - &mut self, - name: String, - variable_type: UserDefinedType, - ) -> Result<(), SymbolTableError> { - // Check that the circuit name is unique. - match self.insert_name(name, variable_type) { - Some(duplicate) => Err(SymbolTableError::duplicate_function(duplicate)), - None => Ok(()), - } - } - - /// - /// Insert a circuit definition into the symbol table from a given circuit identifier and - /// circuit type. - /// - /// If the symbol table did not have this name present, `None` is returned. - /// If the symbol table did have this name present, the circuit type is updated, and the old - /// circuit type is returned. - /// - pub fn insert_circuit_type(&mut self, identifier: Identifier, circuit_type: CircuitType) -> Option { - self.circuits.insert(identifier.name, circuit_type) - } - - /// - /// Insert a function definition into the symbol table from a given identifier and - /// function type. - /// - /// If the symbol table did not have this name present, `None` is returned. - /// If the symbol table did have this name present, the function type is updated, and the old - /// function type is returned. - /// - pub fn insert_function_type( - &mut self, - identifier: Identifier, - function_type: FunctionType, - ) -> Option { - self.functions.insert(identifier.name, function_type) - } - - /// - /// Insert all circuit and function types from another symbol table. - /// Used when importing names from another package. - /// - pub fn insert_table_types(&mut self, imported: &Self) -> Result<(), SymbolTableError> { - for (imported_circuit_name, imported_circuit_type) in imported.circuits.iter() { - self.circuits - .insert(imported_circuit_name.to_owned(), imported_circuit_type.to_owned()); - } - - for (imported_function_name, imported_function_type) in imported.functions.iter() { - self.functions - .insert(imported_function_name.to_owned(), imported_function_type.to_owned()); - } - - Ok(()) - } - - /// - /// Returns a reference to the circuit type corresponding to the name. - /// - /// If the symbol table did not have this name present, then the parent symbol table is checked. - /// If there is no parent symbol table, then `None` is returned. - /// - pub fn get_circuit_type(&self, name: &str) -> Option<&CircuitType> { - // Lookup name in symbol table. - match self.circuits.get(name) { - Some(circuit) => Some(circuit), - None => { - // Lookup name in parent symbol table. - match &self.parent { - Some(parent) => parent.get_circuit_type(name), - None => None, - } - } - } - } - - /// - /// Returns a reference to the function type corresponding to the name. - /// - /// If the symbol table did not have this name present, then the parent symbol table is checked. - /// If there is no parent symbol table, then `None` is returned. - /// - pub fn get_function_type(&self, name: &str) -> Option<&FunctionType> { - // Lookup name in symbol table. - match self.functions.get(name) { - Some(circuit) => Some(circuit), - None => { - // Lookup name in parent symbol table - match &self.parent { - Some(parent) => parent.get_function_type(name), - None => None, - } - } - } - } - - /// - /// Checks for duplicate import, circuit, and function names given a program. - /// - /// If a circuit or function name has no duplicates, then it is inserted into the symbol table. - /// Variables defined later in the unresolved program cannot have the same name. - /// - pub fn check_names( - &mut self, - program: &Program, - import_parser: &ImportParser, - input: &Input, - ) -> Result<(), SymbolTableError> { - // Check unresolved program import names. - self.check_import_names(&program.imports, import_parser, input)?; - - // Check unresolved program circuit names. - self.check_circuit_names(&program.circuits)?; - - // Check unresolved program function names. - self.check_function_names(&program.functions)?; - - Ok(()) - } - - /// - /// Checks for duplicate circuit names given a hashmap of circuits. - /// - /// If a circuit name has no duplicates, then it is inserted into the symbol table. - /// Types defined later in the program cannot have the same name. - /// - pub fn check_circuit_names(&mut self, circuits: &IndexMap) -> Result<(), SymbolTableError> { - // Iterate over circuit names and definitions. - for (identifier, circuit) in circuits.iter() { - // Attempt to insert the circuit name into the symbol table. - self.insert_circuit_name(identifier.to_string(), UserDefinedType::from(circuit.clone()))?; - } - - Ok(()) - } - - /// - /// Checks for duplicate function names given a hashmap of functions. - /// - /// If a function name has no duplicates, then it is inserted into the symbol table. - /// Types defined later in the program cannot have the same name. - /// - pub fn check_function_names(&mut self, functions: &IndexMap) -> Result<(), SymbolTableError> { - // Iterate over function names and definitions. - for (identifier, function) in functions.iter() { - // Attempt to insert the function name into the symbol table. - self.insert_function_name(identifier.to_string(), UserDefinedType::from(function.clone()))?; - } - - Ok(()) - } - - /// - /// Checks that all given imported names exist in the list of imported programs. - /// - /// Additionally checks for duplicate imported names in the given vector of imports. - /// Types defined later in the program cannot have the same name. - /// - pub fn check_import_names( - &mut self, - imports: &[ImportStatement], - import_parser: &ImportParser, - input: &Input, - ) -> Result<(), SymbolTableError> { - // Iterate over imported names. - for import in imports { - self.check_import_statement(import, import_parser, input)?; - } - - Ok(()) - } - - /// - /// Checks that a given import statement imports an existing package. - /// - /// Additionally checks for duplicate imported names in the given vector of imports. - /// Types defined later in the program cannot have the same name. - /// - pub fn check_import_statement( - &mut self, - import: &ImportStatement, - import_parser: &ImportParser, - input: &Input, - ) -> Result<(), SymbolTableError> { - // Check if the import name exists as core package. - let core_package = import_parser.get_core_package(&import.package); - - // If the core package exists, then attempt to insert the import into the symbol table. - if let Some(package) = core_package { - return self.check_core_package(package); - } - - // Attempt to insert the imported names into the symbol table. - self.check_package(import, import_parser, input) - } - - /// - /// Inserts imported core package circuit names and types into the symbol table. - /// - /// Checks that the core package and all circuit names exist. Checks that imported circuit types - /// only contain known types. - /// - pub fn check_core_package(&mut self, package: &Package) -> Result<(), SymbolTableError> { - // Create list of imported core packages. - let list = CorePackageList::from_package_access(package.access.to_owned())?; - - // Fetch core package symbols from `leo-core`. - let symbol_list = list.to_symbols()?; - - // Insert name and type information for each core package symbol. - for (name, circuit) in symbol_list.symbols() { - // Store name of symbol. - self.insert_circuit_name(name.to_string(), UserDefinedType::from(circuit.clone()))?; - - // Create new circuit type for symbol. - let circuit_type = CircuitType::new(&self, circuit.to_owned())?; - - // Insert circuit type of symbol. - self.insert_circuit_type(circuit_type.identifier.clone(), circuit_type); - } - - Ok(()) - } - - /// - /// Inserts one or more imported symbols for a given imported package. - /// - /// Checks that the package and all circuit and function names exist. Checks that imported circuit - /// and function types only contain known types. - /// - pub fn check_package( - &mut self, - import: &ImportStatement, - import_parser: &ImportParser, - input: &Input, - ) -> Result<(), SymbolTableError> { - // Get imported symbols from statement. - let imported_symbols = ImportedSymbols::new(import); - - // Import all symbols from an imported file for now. - // Keep track of which import files have already been checked. - let mut checked = IndexSet::new(); - - // Iterate over each imported symbol. - for (name, symbol) in imported_symbols.symbols { - // Find the imported program. - let program = import_parser - .get_import(&name) - .ok_or_else(|| SymbolTableError::unknown_package(&name, &symbol.span))?; - - // Push the imported file's name to checked import files. - if !checked.insert(name) { - // Skip the imported symbol if we have already checked the file. - continue; - }; - - // Check the imported program for duplicate or undefined types. - let import_symbol_table = SymbolTable::new(program, import_parser, input)?; - - // Import symbols into the self symbol table. - self.insert_import_symbol(symbol, import_symbol_table, program)?; - } - - Ok(()) - } - - /// - /// Inserts the imported symbol into the symbol table if it is present in the given program. - /// - pub fn insert_import_symbol( - &mut self, - symbol: ImportSymbol, - table: SymbolTable, - program: &Program, - ) -> Result<(), SymbolTableError> { - // Check for import *. - if symbol.is_star() { - // Insert all program circuits and functions. - self.insert_table_types(&table) - } else { - // Check for a symbol alias. - let identifier = symbol.alias.to_owned().unwrap_or_else(|| symbol.symbol.clone()); - - // Check if the imported symbol is a circuit or a function. - if let Some(circuit_type) = table.get_circuit_type(&symbol.symbol.name) { - // Insert the circuit into the self symbol table. - self.insert_circuit_type(identifier, circuit_type.to_owned()); - - Ok(()) - } else if let Some(function_type) = table.get_function_type(&symbol.symbol.name) { - // Insert the function into the self symbol table. - self.insert_function_type(identifier, function_type.to_owned()); - - Ok(()) - } else { - // Return an error if we cannot find the imported symbol. - Err(SymbolTableError::unknown_symbol(&symbol, program)) - } - } - } - - /// - /// Checks for unknown types in circuit and function definitions given an unresolved program. - /// - /// If a circuit or function definition only contains known types, then it is inserted into the - /// symbol table. Variables defined later in the unresolved program can lookup the definition and - /// refer to its expected types. - /// - pub fn check_types(&mut self, program: &Program) -> Result<(), SymbolTableError> { - // Check unresolved program circuit definitions. - self.check_types_circuits(&program.circuits)?; - - // Check unresolved program function definitions. - self.check_types_functions(&program.functions)?; - - Ok(()) - } - - /// - /// Checks for unknown types in a circuit given a hashmap of circuits. - /// - /// If a circuit definition only contains known types, then it is inserted into the - /// symbol table. Variables defined later in the program can lookup the definition - /// and refer to its expected types - /// - pub fn check_types_circuits(&mut self, circuits: &IndexMap) -> Result<(), SymbolTableError> { - // Iterate over circuit names and definitions. - for circuit in circuits.values() { - // Get the identifier of the circuit. - let identifier = circuit.circuit_name.clone(); - - // Resolve unknown types in the circuit definition. - let circuit_type = CircuitType::new(self, circuit.clone())?; - - // Attempt to insert the circuit definition into the symbol table. - self.insert_circuit_type(identifier, circuit_type); - } - - Ok(()) - } - - /// - /// Checks for unknown types in a function given a hashmap of functions. - /// - /// If a function definition only contains known types, then it is inserted into the - /// symbol table. Variables defined later in the program can lookup the definition - /// and refer to its expected types - /// - pub fn check_types_functions( - &mut self, - functions: &IndexMap, - ) -> Result<(), SymbolTableError> { - // Iterate over function names and definitions. - for function in functions.values() { - // Get the identifier of the function. - let identifier = function.identifier.clone(); - - // Resolve unknown types in the function definition. - let function_type = FunctionType::new(&self, function.clone())?; - - // Attempt to insert the function definition into the symbol table. - self.insert_function_type(identifier, function_type); - } - - Ok(()) - } - - /// - /// Inserts function input types into the symbol table. - /// - /// Creates a new `CircuitType` to represent the input values. - /// The new type contains register, record, state, and state leaf circuit variables. - /// This allows easy access to input types using dot syntax: `input.register.r0`. - /// - pub fn insert_input(&mut self, input: &Input) -> Result<(), SymbolTableError> { - // Get values for each input section. - let registers_values = input.get_registers().values(); - let record_values = input.get_record().values(); - let state_values = input.get_state().values(); - let state_leaf_values = input.get_state_leaf().values(); - - // Create a new `CircuitType` for each input section. - let registers_type = - CircuitType::from_input_section(&self, REGISTERS_VARIABLE_NAME.to_string(), registers_values)?; - let record_type = CircuitType::from_input_section(&self, RECORD_VARIABLE_NAME.to_string(), record_values)?; - let state_type = CircuitType::from_input_section(&self, STATE_VARIABLE_NAME.to_string(), state_values)?; - let state_leaf_type = - CircuitType::from_input_section(&self, STATE_LEAF_VARIABLE_NAME.to_string(), state_leaf_values)?; - - // Create a new `CircuitVariableType` for each type. - let registers_variable = CircuitVariableType::from(®isters_type); - let record_variable = CircuitVariableType::from(&record_type); - let state_variable = CircuitVariableType::from(&state_type); - let state_leaf_variable = CircuitVariableType::from(&state_leaf_type); - - // Create new `CircuitType` for input keyword. - let input_type = CircuitType { - identifier: Identifier::new(INPUT_VARIABLE_NAME.to_string()), - variables: vec![registers_variable, record_variable, state_variable, state_leaf_variable], - functions: Vec::new(), - }; - - // Insert each circuit type into the symbol table. - self.insert_circuit_type(registers_type.identifier.clone(), registers_type); - self.insert_circuit_type(record_type.identifier.clone(), record_type); - self.insert_circuit_type(state_type.identifier.clone(), state_type); - self.insert_circuit_type(state_leaf_type.identifier.clone(), state_leaf_type); - self.insert_circuit_type(input_type.identifier.clone(), input_type); - - Ok(()) - } -} diff --git a/symbol-table/src/types/circuits/circuit.rs b/symbol-table/src/types/circuits/circuit.rs deleted file mode 100644 index af5ab9052d..0000000000 --- a/symbol-table/src/types/circuits/circuit.rs +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright (C) 2019-2021 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::{types::circuits::CircuitVariableType, FunctionType, SymbolTable, Type, TypeError}; -use leo_ast::{Circuit, CircuitMember, Identifier, InputValue, Parameter, Span}; - -use indexmap::IndexMap; -use serde::{Deserialize, Serialize}; -use std::hash::{Hash, Hasher}; - -/// Stores circuit definition details. -/// -/// This type should be added to the circuit symbol table for a resolved syntax tree. -/// This is a user-defined type. -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct CircuitType { - /// The name of the circuit definition. - pub identifier: Identifier, - - /// The circuit variables. - pub variables: Vec, - - /// The circuit functions. - pub functions: Vec, -} - -impl CircuitType { - /// - /// Return a new `CircuitType` from a given `Circuit` definition. - /// - /// Performs a lookup in the given symbol table if the circuit definition contains - /// user-defined types. - /// - pub fn new(table: &SymbolTable, unresolved: Circuit) -> Result { - let circuit_identifier = unresolved.circuit_name; - let mut variables = vec![]; - let mut functions = vec![]; - - // Resolve the type of every circuit member. - for member in unresolved.members { - match member { - CircuitMember::CircuitVariable(variable_identifier, type_) => { - // Resolve the type of the circuit member variable. - let type_ = Type::new_from_circuit( - table, - type_, - circuit_identifier.clone(), - circuit_identifier.span.clone(), - )?; - - // Create a new circuit variable type. - let variable = CircuitVariableType { - identifier: variable_identifier, - type_, - attribute: None, - }; - - // Store the circuit variable type. - variables.push(variable); - } - CircuitMember::CircuitFunction(function) => { - // Resolve the type of the circuit member function. - let function_type = FunctionType::from_circuit(table, circuit_identifier.clone(), function)?; - - // Store the circuit function type. - functions.push(function_type); - } - } - } - - // Return a new circuit type. - Ok(CircuitType { - identifier: circuit_identifier, - variables, - functions, - }) - } - - /// - /// Returns the function type of a circuit member given an identifier. - /// - pub fn member_function_type(&self, identifier: &Identifier) -> Option<&FunctionType> { - self.functions - .iter() - .find(|function| function.identifier.eq(identifier)) - } - - /// - /// Returns the type of a circuit member. - /// - /// If the member is a circuit variable, then the type of the variable is returned. - /// If the member is a circuit function, then the return type of the function is returned. - /// - pub fn member_type(&self, identifier: &Identifier) -> Result { - // Check if the circuit member is a circuit variable. - let matched_variable = self - .variables - .iter() - .find(|variable| variable.identifier.eq(identifier)); - - match matched_variable { - Some(variable) => Ok(variable.type_.to_owned()), - None => { - // Check if the circuit member is a circuit function. - let matched_function = self.member_function_type(identifier); - - match matched_function { - Some(function) => Ok(Type::Function(function.identifier.to_owned())), - None => Err(TypeError::undefined_circuit_member(identifier.clone())), - } - } - } - } - - /// - /// Returns a new `CircuitType` from a given `Input` struct. - /// - pub fn from_input_section( - table: &SymbolTable, - name: String, - section: IndexMap>, - ) -> Result { - // Create a new `CircuitVariableType` for each section pair. - let mut variables = Vec::new(); - - for (parameter, _option) in section.into_iter() { - let variable = CircuitVariableType { - identifier: parameter.variable, - type_: Type::new(table, parameter.type_, Span::default())?, - attribute: None, - }; - - variables.push(variable); - } - - // Create a new `Identifier` for the input section. - let identifier = Identifier::new(name); - - // Return a new `CircuitType` with the given name. - Ok(Self { - identifier, - variables, - functions: Vec::new(), - }) - } -} - -impl PartialEq for CircuitType { - fn eq(&self, other: &Self) -> bool { - self.identifier.eq(&other.identifier) - } -} - -impl Eq for CircuitType {} - -impl Hash for CircuitType { - fn hash(&self, state: &mut H) { - self.identifier.hash(state); - } -} diff --git a/symbol-table/src/types/circuits/circuit_variable.rs b/symbol-table/src/types/circuits/circuit_variable.rs deleted file mode 100644 index 8f63acb232..0000000000 --- a/symbol-table/src/types/circuits/circuit_variable.rs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (C) 2019-2021 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::{Attribute, CircuitType, Type}; -use leo_ast::Identifier; - -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct CircuitVariableType { - /// The name of the circuit variable - pub identifier: Identifier, - /// The type of the circuit variable - pub type_: Type, - /// The attribute of the circuit variable - pub attribute: Option, -} - -impl From<&CircuitType> for CircuitVariableType { - fn from(type_: &CircuitType) -> Self { - Self { - identifier: type_.identifier.clone(), - type_: Type::Circuit(type_.identifier.clone()), - attribute: None, - } - } -} diff --git a/symbol-table/src/types/circuits/mod.rs b/symbol-table/src/types/circuits/mod.rs deleted file mode 100644 index fabb21e6b1..0000000000 --- a/symbol-table/src/types/circuits/mod.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (C) 2019-2021 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 . - -pub mod circuit; -pub use self::circuit::*; - -pub mod circuit_variable; -pub use self::circuit_variable::*; diff --git a/symbol-table/src/types/functions/function.rs b/symbol-table/src/types/functions/function.rs deleted file mode 100644 index 0d5f50ee41..0000000000 --- a/symbol-table/src/types/functions/function.rs +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright (C) 2019-2021 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::{ - types::functions::{FunctionInputType, FunctionOutputType}, - SymbolTable, - TypeError, -}; -use leo_ast::{Function, Identifier}; - -use serde::{Deserialize, Serialize}; -use std::hash::{Hash, Hasher}; - -/// Stores function definition details. -/// -/// This type should be added to the function symbol table for a resolved syntax tree. -/// This is a user-defined type. -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct FunctionType { - /// The name of the function definition. - pub identifier: Identifier, - - /// The function inputs. - pub inputs: Vec, - - /// The function output. - pub output: FunctionOutputType, -} - -impl FunctionType { - /// - /// Return a new `FunctionType` from a given `Function` definition. - /// - /// Performs a lookup in the given symbol table if the function definition contains - /// user-defined types. - /// - pub fn new(table: &SymbolTable, unresolved: Function) -> Result { - let mut inputs_resolved = Vec::with_capacity(unresolved.input.len()); - - // Type check function inputs - for input in unresolved.input { - let input = FunctionInputType::new(table, input)?; - inputs_resolved.push(input); - } - - // Type check function output - let output = FunctionOutputType::new(table, unresolved.output, unresolved.span)?; - - Ok(FunctionType { - identifier: unresolved.identifier, - inputs: inputs_resolved, - output, - }) - } - - /// - /// Return a new `FunctionType` from a given `Function` definition. - /// - /// Performs a lookup in the given symbol table if the function definition contains - /// user-defined types. - /// - /// If the function definition contains the `Self` keyword, then the given circuit identifier - /// is used as the type. - /// - pub fn from_circuit( - table: &SymbolTable, - circuit_name: Identifier, - unresolved_function: Function, - ) -> Result { - let function_identifier = unresolved_function.identifier; - let mut inputs = Vec::with_capacity(unresolved_function.input.len()); - - // Type check function inputs. - for unresolved_input in unresolved_function.input { - let input = FunctionInputType::new_from_circuit(table, unresolved_input, circuit_name.clone())?; - inputs.push(input); - } - - // Type check function output. - let output = FunctionOutputType::new_from_circuit( - table, - circuit_name, - unresolved_function.output, - unresolved_function.span, - )?; - - Ok(FunctionType { - identifier: function_identifier, - inputs, - output, - }) - } - - /// - /// Resolve a function definition and insert it into the given symbol table. - /// - pub fn insert_definition(table: &mut SymbolTable, unresolved_function: Function) -> Result<(), TypeError> { - // Get the identifier of the function. - let function_identifier = unresolved_function.identifier.clone(); - - // Resolve the function definition into a function type. - let function = Self::new(table, unresolved_function)?; - - // Insert (function_identifier -> function_type) as a (key -> value) pair in the symbol table. - table.insert_function_type(function_identifier, function); - - Ok(()) - } - - /// - /// Returns `true` if the input `self` or `mut self` is present. - /// Returns `false` otherwise. - /// - pub fn contains_self(&self) -> bool { - self.inputs.iter().any(|param| param.is_self()) - } - - /// - /// Returns an iterator of [&FunctionInputType] removing `self` and `mut self` inputs. - /// - pub fn filter_self_inputs(&self) -> impl Iterator { - self.inputs.iter().filter(|input| !input.is_self()) - } - - /// - /// Returns the number of input variables to the function. - /// The `self` and `mut self` keywords are not counted as input variables. - /// - pub fn num_inputs(&self) -> usize { - self.filter_self_inputs().count() - } -} - -impl PartialEq for FunctionType { - fn eq(&self, other: &Self) -> bool { - self.identifier.eq(&other.identifier) - } -} - -impl Eq for FunctionType {} - -impl Hash for FunctionType { - fn hash(&self, state: &mut H) { - self.identifier.hash(state); - } -} diff --git a/symbol-table/src/types/functions/function_input.rs b/symbol-table/src/types/functions/function_input.rs deleted file mode 100644 index c0147a6c04..0000000000 --- a/symbol-table/src/types/functions/function_input.rs +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright (C) 2019-2021 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::{FunctionInputVariableType, SymbolTable, Type, TypeError}; -use leo_ast::{FunctionInput, Identifier, Span}; - -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub enum FunctionInputType { - InputKeyword(Identifier), - SelfKeyword(Identifier), - MutSelfKeyword(Identifier), - Variable(FunctionInputVariableType), -} - -impl FunctionInputType { - /// - /// Return the `Identifier` containing name and span information about the current function input. - /// - pub fn identifier(&self) -> &Identifier { - match self { - FunctionInputType::InputKeyword(identifier) => identifier, - FunctionInputType::SelfKeyword(identifier) => identifier, - FunctionInputType::MutSelfKeyword(identifier) => identifier, - FunctionInputType::Variable(variable) => &variable.identifier, - } - } - - /// - /// Return the `Type` of the current function input. - /// - pub fn type_(&self) -> Type { - match self { - FunctionInputType::InputKeyword(identifier) => Type::Circuit(identifier.to_owned()), - FunctionInputType::SelfKeyword(identifier) => Type::Circuit(identifier.to_owned()), - FunctionInputType::MutSelfKeyword(identifier) => Type::Circuit(identifier.to_owned()), - FunctionInputType::Variable(variable) => variable.type_.to_owned(), - } - } - - /// - /// Return the `Span` of the current function input. - /// - pub fn span(&self) -> &Span { - match self { - FunctionInputType::InputKeyword(identifier) => &identifier.span, - FunctionInputType::SelfKeyword(identifier) => &identifier.span, - FunctionInputType::MutSelfKeyword(identifier) => &identifier.span, - FunctionInputType::Variable(variable) => &variable.span, - } - } - - /// - /// Returns `true` if input `self` or `mut self` is present. - /// Returns `false` otherwise. - /// - pub fn is_self(&self) -> bool { - match self { - FunctionInputType::InputKeyword(_) => false, - FunctionInputType::SelfKeyword(_) => true, - FunctionInputType::MutSelfKeyword(_) => true, - FunctionInputType::Variable(_) => false, - } - } - - /// - /// Return a new `FunctionInputType` from a given `FunctionInput`. - /// - /// Performs a lookup in the given symbol table if the function input contains - /// user-defined types. - /// - pub fn new(table: &SymbolTable, unresolved: FunctionInput) -> Result { - Ok(match unresolved { - FunctionInput::InputKeyword(keyword) => FunctionInputType::InputKeyword(Identifier::from(keyword)), - FunctionInput::SelfKeyword(_) => unimplemented!("cannot call self keyword from non-circuit context"), - FunctionInput::MutSelfKeyword(_) => unimplemented!("cannot call mut self keyword from non-circuit context"), - FunctionInput::Variable(variable) => { - let variable_resolved = FunctionInputVariableType::new(table, variable)?; - - FunctionInputType::Variable(variable_resolved) - } - }) - } - - /// - /// Return a new `FunctionInputType` from a given `FunctionInput`. - /// - /// Performs a lookup in the given symbol table if the function input contains - /// user-defined types. - /// - /// If the type of the function input is the `Self` keyword, then the given circuit identifier - /// is used as the type. - /// - pub fn new_from_circuit( - table: &SymbolTable, - unresolved: FunctionInput, - circuit_name: Identifier, - ) -> Result { - Ok(match unresolved { - FunctionInput::InputKeyword(keyword) => FunctionInputType::InputKeyword(Identifier::from(keyword)), - FunctionInput::SelfKeyword(keyword) => { - FunctionInputType::SelfKeyword(Identifier::new_with_span(&circuit_name.name, &keyword.span)) - } - FunctionInput::MutSelfKeyword(keyword) => { - FunctionInputType::MutSelfKeyword(Identifier::new_with_span(&circuit_name.name, &keyword.span)) - } - FunctionInput::Variable(unresolved_function_input) => { - let function_input = - FunctionInputVariableType::new_from_circuit(table, unresolved_function_input, circuit_name)?; - - FunctionInputType::Variable(function_input) - } - }) - } -} diff --git a/symbol-table/src/types/functions/function_input_variable.rs b/symbol-table/src/types/functions/function_input_variable.rs deleted file mode 100644 index b1e63b494a..0000000000 --- a/symbol-table/src/types/functions/function_input_variable.rs +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (C) 2019-2021 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::{Attribute, SymbolTable, Type, TypeError}; -use leo_ast::{FunctionInputVariable, Identifier, Span}; - -use serde::{Deserialize, Serialize}; -use std::hash::{Hash, Hasher}; - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct FunctionInputVariableType { - /// Name of function input. - pub identifier: Identifier, - - /// Type of function input. - pub type_: Type, - - /// The attributes of the function input. - pub attribute: Option, - - /// The span of the function input. - pub span: Span, -} - -impl FunctionInputVariableType { - /// - /// Return a new `FunctionInputVariableType` from a given `FunctionInputVariable`. - /// - /// Performs a lookup in the given symbol table if the type is user-defined. - /// - pub fn new(table: &SymbolTable, unresolved: FunctionInputVariable) -> Result { - let type_ = Type::new(table, unresolved.type_, unresolved.span.clone())?; - let attribute = if unresolved.mutable { - Some(Attribute::Mutable) - } else { - None - }; - - Ok(FunctionInputVariableType { - identifier: unresolved.identifier, - type_, - attribute, - span: unresolved.span, - }) - } - - /// - /// Return a new `FunctionInputVariableType` from a given `FunctionInputVariable`. - /// - /// Performs a lookup in the given symbol table if the type is user-defined. - /// - /// If the type of the function return type is the `Self` keyword, then the given circuit - /// identifier is used as the type. - /// - pub fn new_from_circuit( - table: &SymbolTable, - unresolved_function_input: FunctionInputVariable, - circuit_name: Identifier, - ) -> Result { - let type_ = Type::new_from_circuit( - table, - unresolved_function_input.type_, - circuit_name, - unresolved_function_input.span.clone(), - )?; - - let attribute = if unresolved_function_input.mutable { - Some(Attribute::Mutable) - } else { - None - }; - - Ok(FunctionInputVariableType { - identifier: unresolved_function_input.identifier, - type_, - attribute, - span: unresolved_function_input.span, - }) - } -} - -impl PartialEq for FunctionInputVariableType { - fn eq(&self, other: &Self) -> bool { - self.identifier.eq(&other.identifier) - } -} - -impl Eq for FunctionInputVariableType {} - -impl Hash for FunctionInputVariableType { - fn hash(&self, state: &mut H) { - self.identifier.hash(state) - } -} diff --git a/symbol-table/src/types/functions/function_output.rs b/symbol-table/src/types/functions/function_output.rs deleted file mode 100644 index 43919b10a3..0000000000 --- a/symbol-table/src/types/functions/function_output.rs +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (C) 2019-2021 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::{SymbolTable, Type, TypeError}; - -use leo_ast::{Identifier, Span, Type as UnresolvedType}; - -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct FunctionOutputType { - /// Type of function output. - pub type_: Type, -} - -impl FunctionOutputType { - /// - /// Return a new `FunctionOutputType` from a given optional function return type and span. - /// - /// Performs a lookup in the given symbol table if the return type is user-defined. - /// - pub(crate) fn new( - table: &SymbolTable, - function_output: Option, - span: Span, - ) -> Result { - let type_ = match function_output { - None => Type::Tuple(vec![]), // functions with no return value return an empty tuple - Some(type_) => Type::new(table, type_, span)?, - }; - - Ok(FunctionOutputType { type_ }) - } - - /// - /// Return a new `FunctionOutputType` from a given optional function return type and span. - /// - /// Performs a lookup in the given symbol table if the return type is user-defined. - /// - /// If the type of the function return type is the `Self` keyword, then the given circuit - /// identifier is used as the type. - /// - pub fn new_from_circuit( - table: &SymbolTable, - circuit_name: Identifier, - unresolved: Option, - span: Span, - ) -> Result { - let output_type = match unresolved { - None => Type::Tuple(vec![]), - Some(type_) => Type::new_from_circuit(table, type_, circuit_name, span)?, - }; - - Ok(FunctionOutputType { type_: output_type }) - } -} diff --git a/symbol-table/src/types/functions/mod.rs b/symbol-table/src/types/functions/mod.rs deleted file mode 100644 index dbfc40c7dc..0000000000 --- a/symbol-table/src/types/functions/mod.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (C) 2019-2021 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 . - -pub mod function; -pub use self::function::*; - -pub mod function_input; -pub use self::function_input::*; - -pub mod function_input_variable; -pub use self::function_input_variable::*; - -pub mod function_output; -pub use self::function_output::*; diff --git a/symbol-table/src/types/mod.rs b/symbol-table/src/types/mod.rs deleted file mode 100644 index c8c083d597..0000000000 --- a/symbol-table/src/types/mod.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (C) 2019-2021 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 . - -pub mod circuits; -pub use self::circuits::*; - -pub mod functions; -pub use self::functions::*; - -pub mod type_; -pub use self::type_::*; - -pub mod type_variable; -pub use self::type_variable::*; - -pub mod user_defined; -pub use self::user_defined::*; diff --git a/symbol-table/src/types/type_.rs b/symbol-table/src/types/type_.rs deleted file mode 100644 index 652310ae9e..0000000000 --- a/symbol-table/src/types/type_.rs +++ /dev/null @@ -1,265 +0,0 @@ -// Copyright (C) 2019-2021 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::{SymbolTable, TypeError, TypeVariable}; -use leo_ast::{Identifier, IntegerType, Span, Type as UnresolvedType}; - -use serde::{Deserialize, Serialize}; -use std::{ - cmp::{Eq, PartialEq}, - fmt, -}; - -/// A type in a Leo program. -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum Type { - // Data types - Address, - Boolean, - Field, - Group, - IntegerType(IntegerType), - - // Data type wrappers - Array(Box), - Tuple(Vec), - - // User defined types - Circuit(Identifier), - Function(Identifier), - - // Unknown type variables - TypeVariable(TypeVariable), -} - -impl Type { - /// - /// Return a new type from the given unresolved type. - /// - /// Performs a lookup in the given symbol table if the type is user-defined. - /// - pub fn new(table: &SymbolTable, type_: UnresolvedType, span: Span) -> Result { - Ok(match type_ { - UnresolvedType::Address => Type::Address, - UnresolvedType::Boolean => Type::Boolean, - UnresolvedType::Field => Type::Field, - UnresolvedType::Group => Type::Group, - UnresolvedType::IntegerType(integer) => Type::IntegerType(integer), - - UnresolvedType::Array(type_, _) => { - let array_type = Type::new(table, *type_, span)?; - - Type::Array(Box::new(array_type)) - } - UnresolvedType::Tuple(types) => { - let tuple_types = types - .into_iter() - .map(|type_| Type::new(table, type_, span.clone())) - .collect::, _>>()?; - - Type::Tuple(tuple_types) - } - - UnresolvedType::Circuit(identifier) => { - // Lookup the circuit type in the symbol table - let circuit_type = table - .get_circuit_type(&identifier.name) - .ok_or_else(|| TypeError::undefined_circuit(identifier))?; - - Type::Circuit(circuit_type.identifier.clone()) - } - - UnresolvedType::SelfType => { - // Throw an error for using `Self` outside of a circuit - return Err(TypeError::self_not_available(span)); - } - }) - } - - /// - /// Return a new type from the given unresolved type. - /// - /// If this type is SelfType, return the circuit's type. - /// - pub fn new_from_circuit( - table: &SymbolTable, - type_: UnresolvedType, - circuit_name: Identifier, - span: Span, - ) -> Result { - Ok(match type_ { - UnresolvedType::Array(type_, _) => { - let array_type = Type::new_from_circuit(table, *type_, circuit_name, span)?; - Type::Array(Box::new(array_type)) - } - UnresolvedType::Tuple(types) => { - let tuple_types = types - .into_iter() - .map(|type_| Type::new_from_circuit(table, type_, circuit_name.clone(), span.clone())) - .collect::, _>>()?; - - Type::Tuple(tuple_types) - } - UnresolvedType::SelfType => Type::Circuit(circuit_name), - // The unresolved type does not depend on the current circuit definition - unresolved => Type::new(table, unresolved, span)?, - }) - } - - /// Returns a list of signed integer types. - pub const fn signed_integer_types() -> [Type; 5] { - [ - Type::IntegerType(IntegerType::I8), - Type::IntegerType(IntegerType::I16), - Type::IntegerType(IntegerType::I32), - Type::IntegerType(IntegerType::I64), - Type::IntegerType(IntegerType::I128), - ] - } - - /// Returns a list of unsigned integer types. - pub const fn unsigned_integer_types() -> [Type; 5] { - [ - Type::IntegerType(IntegerType::U8), - Type::IntegerType(IntegerType::U16), - Type::IntegerType(IntegerType::U32), - Type::IntegerType(IntegerType::U64), - Type::IntegerType(IntegerType::U128), - ] - } - - /// Returns a list of positive integer types. - pub fn negative_integer_types() -> Vec { - let field_group = [Type::Field, Type::Group]; - - let mut types = Vec::new(); - - types.extend_from_slice(&field_group); - types.extend_from_slice(&Self::signed_integer_types()); - - types - } - - /// Returns a list of integer types. - pub fn integer_types() -> Vec { - let mut types = Vec::new(); - - types.extend_from_slice(&Self::unsigned_integer_types()); - types.extend_from_slice(&Self::negative_integer_types()); - - types - } - - /// Returns a list of possible index types (u8, u16, u32). - pub fn index_types() -> Vec { - let index_types = [ - Type::IntegerType(IntegerType::U8), - Type::IntegerType(IntegerType::U16), - Type::IntegerType(IntegerType::U32), - ]; - - let mut types = Vec::new(); - - types.extend_from_slice(&index_types); - - types - } - - /// - /// Replaces self with the given type if self is equal to the given `TypeVariable`. - /// - pub fn substitute(&mut self, variable: &TypeVariable, type_: &Type) { - match self { - Type::TypeVariable(self_variable) => { - if self_variable == variable { - *self = type_.to_owned() - } - } - Type::Array(self_type) => { - self_type.substitute(variable, type_); - } - Type::Tuple(types) => types - .iter_mut() - .for_each(|tuple_type| tuple_type.substitute(variable, type_)), - _ => {} - } - } -} - -impl fmt::Display for Type { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match &self { - Type::Address => write!(f, "address"), - Type::Boolean => write!(f, "bool"), - Type::Field => write!(f, "field"), - Type::Group => write!(f, "group"), - Type::IntegerType(integer_type) => write!(f, "{}", integer_type), - - Type::Array(type_) => write!(f, "[{}]", *type_), - Type::Tuple(tuple) => { - let tuple_string = tuple.iter().map(|x| x.to_string()).collect::>().join(", "); - - write!(f, "({})", tuple_string) - } - - Type::Circuit(identifier) => write!(f, "circuit {}", identifier), - Type::Function(identifier) => write!(f, "function {}", identifier), - Type::TypeVariable(type_variable) => write!(f, "{}", type_variable), - } - } -} - -impl PartialEq for Type { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Type::Address, Type::Address) => true, - (Type::Boolean, Type::Boolean) => true, - (Type::Field, Type::Field) => true, - (Type::Group, Type::Group) => true, - (Type::IntegerType(integer_type1), Type::IntegerType(integer_type2)) => integer_type1.eq(integer_type2), - - (Type::Array(array1), Type::Array(array2)) => { - // Get both array element types before comparison. - let array1_element = get_array_element_type(array1); - let array2_element = get_array_element_type(array2); - - // Check that both arrays have the same element type. - array1_element.eq(array2_element) - } - - (Type::Tuple(types1), Type::Tuple(types2)) => types1.eq(types2), - (Type::Circuit(identifier1), Type::Circuit(identifier2)) => identifier1.eq(identifier2), - (Type::Function(identifier1), Type::Function(identifier2)) => identifier1.eq(identifier2), - (Type::TypeVariable(variable1), Type::TypeVariable(variable2)) => variable1.eq(variable2), - _ => false, - } - } -} - -impl Eq for Type {} - -/// -/// Returns the data type of the array element. -/// -/// If the given `type_` is an array, call `get_array_element_type()` on the array element type. -/// If the given `type_` is any other type, return the `type_`. -/// -pub fn get_array_element_type(type_: &Type) -> &Type { - if let Type::Array(element_type) = type_ { - get_array_element_type(element_type) - } else { - type_ - } -} diff --git a/symbol-table/src/types/type_variable.rs b/symbol-table/src/types/type_variable.rs deleted file mode 100644 index 7a20d66f9e..0000000000 --- a/symbol-table/src/types/type_variable.rs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (C) 2019-2021 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 leo_ast::Identifier; - -use serde::{Deserialize, Serialize}; -use std::fmt; - -/// An unknown type in a Leo program. -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct TypeVariable { - identifier: Identifier, -} - -impl fmt::Display for TypeVariable { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.identifier) - } -} - -impl From for TypeVariable { - fn from(identifier: Identifier) -> Self { - Self { identifier } - } -} - -/// Compare the type variable `Identifier` and `Span`. -impl PartialEq for TypeVariable { - fn eq(&self, other: &Self) -> bool { - self.identifier.name.eq(&other.identifier.name) || self.identifier.span.eq(&other.identifier.span) - } -} - -impl Eq for TypeVariable {} diff --git a/symbol-table/src/types/user_defined/mod.rs b/symbol-table/src/types/user_defined/mod.rs deleted file mode 100644 index 57ea279753..0000000000 --- a/symbol-table/src/types/user_defined/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (C) 2019-2021 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 . - -pub mod user_defined_type; -pub use self::user_defined_type::*; diff --git a/symbol-table/src/types/user_defined/user_defined_type.rs b/symbol-table/src/types/user_defined/user_defined_type.rs deleted file mode 100644 index 2cee495cbc..0000000000 --- a/symbol-table/src/types/user_defined/user_defined_type.rs +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (C) 2019-2021 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::{Attribute, FunctionInputVariableType, Type}; -use leo_ast::{Circuit, Function, Identifier}; - -use std::{ - fmt, - hash::{Hash, Hasher}, -}; - -/// Stores information for a user defined type. -/// -/// User defined types include circuits and functions in a Leo program. -#[derive(Clone, Debug)] -pub struct UserDefinedType { - pub identifier: Identifier, - pub type_: Type, - pub attribute: Option, -} - -impl From for UserDefinedType { - fn from(value: Circuit) -> Self { - let identifier = value.circuit_name; - - UserDefinedType { - identifier: identifier.clone(), - type_: Type::Circuit(identifier), - attribute: None, - } - } -} - -impl From for UserDefinedType { - fn from(value: Function) -> Self { - let identifier = value.identifier; - - UserDefinedType { - identifier: identifier.clone(), - type_: Type::Function(identifier), - attribute: None, - } - } -} - -impl From for UserDefinedType { - fn from(value: FunctionInputVariableType) -> Self { - UserDefinedType { - identifier: value.identifier, - type_: value.type_, - attribute: value.attribute, - } - } -} - -impl fmt::Display for UserDefinedType { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.identifier) - } -} - -impl PartialEq for UserDefinedType { - fn eq(&self, other: &Self) -> bool { - self.identifier.eq(&other.identifier) - } -} - -impl Eq for UserDefinedType {} - -impl Hash for UserDefinedType { - fn hash(&self, state: &mut H) { - self.identifier.hash(state); - } -} diff --git a/symbol-table/tests/mod.rs b/symbol-table/tests/mod.rs deleted file mode 100644 index 361261910c..0000000000 --- a/symbol-table/tests/mod.rs +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (C) 2019-2021 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 . - -pub mod symbol_table; - -use leo_ast::{Ast, Input}; -use leo_grammar::Grammar; -use leo_symbol_table::{SymbolTable, SymbolTableError}; - -use leo_imports::ImportParser; -use std::path::PathBuf; - -const TEST_PROGRAM_PATH: &str = ""; - -/// A helper struct to test a `SymbolTable`. -pub struct TestSymbolTable { - ast: Ast, -} - -impl TestSymbolTable { - /// - /// Returns a Leo syntax tree given a Leo program. - /// - pub fn new(program_string: &str) -> Self { - // Get test file path. - let file_path = PathBuf::from(TEST_PROGRAM_PATH); - - // Get parser syntax tree. - let grammar = Grammar::new(&file_path, program_string).unwrap(); - - // Get Leo syntax tree. - let ast_result = Ast::new(TEST_PROGRAM_PATH, &grammar); - - // We always expect a valid ast for testing. - Self { - ast: ast_result.unwrap(), - } - } - - /// - /// Parse the Leo syntax tree into a symbol table. - /// - /// Expect no errors during parsing. - /// - pub fn expect_success(self, import_parser: ImportParser) { - // Get program. - let program = self.ast.into_repr(); - - // Create empty input. - let input = Input::new(); - - // Create new symbol table. - let _symbol_table = SymbolTable::new(&program, &import_parser, &input).unwrap(); - } - - /// - /// Parse the Leo syntax tree into a symbol table. - /// - /// Expect an error involving entries in the symbol table. - /// - pub fn expect_pass_one_error(self) { - // Get program. - let program = self.ast.into_repr(); - - // Create new symbol table. - let static_check = &mut SymbolTable::default(); - - // Create empty import parser. - let import_parser = ImportParser::default(); - - // Run pass one and expect an error. - let error = static_check - .check_names(&program, &import_parser, &Input::new()) - .unwrap_err(); - - match error { - SymbolTableError::Error(_) => {} // Ok - error => panic!("Expected a symbol table error found `{}`", error), - } - } - - /// - /// Parse the Leo syntax tree into a symbol table. - /// - /// Expect an error involving types in the symbol table. - /// - pub fn expect_pass_two_error(self) { - // Get program. - let program = self.ast.into_repr(); - - // Create a new symbol table. - let static_check = &mut SymbolTable::default(); - - // Create empty import parser. - let import_parser = ImportParser::default(); - - // Run the pass one and expect no errors. - static_check - .check_names(&program, &import_parser, &Input::new()) - .unwrap(); - - // Run the pass two and expect and error. - let error = static_check.check_types(&program).unwrap_err(); - - match error { - SymbolTableError::TypeError(_) => {} //Ok - error => panic!("Expected a type error found `{}`", error), - } - } -} diff --git a/symbol-table/tests/symbol_table/duplicate_circuit.leo b/symbol-table/tests/symbol_table/duplicate_circuit.leo deleted file mode 100644 index de08c207ad..0000000000 --- a/symbol-table/tests/symbol_table/duplicate_circuit.leo +++ /dev/null @@ -1,10 +0,0 @@ -/// -/// Defines a circuit `Foo {}`. -/// Attempts to define a second circuit `Foo {}`. -/// -/// Expected output: SymbolTableError -/// Message: "Duplicate circuit definition found for `Foo`." -/// - -circuit Foo {} -circuit Foo {} \ No newline at end of file diff --git a/symbol-table/tests/symbol_table/duplicate_function.leo b/symbol-table/tests/symbol_table/duplicate_function.leo deleted file mode 100644 index fffbbeff5a..0000000000 --- a/symbol-table/tests/symbol_table/duplicate_function.leo +++ /dev/null @@ -1,10 +0,0 @@ -/// -/// Defines a function `main() {}`. -/// Attempts to define a second function `main() {}`. -/// -/// Expected output: SymbolTableError -/// Message: "Duplicate function definition found for `main`." -/// - -function main() {} -function main() {} \ No newline at end of file diff --git a/symbol-table/tests/symbol_table/import_circuit_alias.leo b/symbol-table/tests/symbol_table/import_circuit_alias.leo deleted file mode 100644 index f0bbc156fd..0000000000 --- a/symbol-table/tests/symbol_table/import_circuit_alias.leo +++ /dev/null @@ -1,9 +0,0 @@ -import bar.Bar as Baz; - -circuit Bar { - r: bool, -} -function main() { - let z = Baz { z: 0u32 }; - let r = Bar { r: true }; -} \ No newline at end of file diff --git a/symbol-table/tests/symbol_table/import_function_alias.leo b/symbol-table/tests/symbol_table/import_function_alias.leo deleted file mode 100644 index 125b2095c8..0000000000 --- a/symbol-table/tests/symbol_table/import_function_alias.leo +++ /dev/null @@ -1,10 +0,0 @@ -import foo.foo as boo; - -function foo() -> bool { - return false -} - -function main() { - let z: u8 = boo(); - let r: bool = foo(); -} \ No newline at end of file diff --git a/symbol-table/tests/symbol_table/import_star.leo b/symbol-table/tests/symbol_table/import_star.leo deleted file mode 100644 index ad7be78c89..0000000000 --- a/symbol-table/tests/symbol_table/import_star.leo +++ /dev/null @@ -1,5 +0,0 @@ -import foo.*; - -function main() { - let x: u8 = boo(); -} \ No newline at end of file diff --git a/symbol-table/tests/symbol_table/import_undefined.leo b/symbol-table/tests/symbol_table/import_undefined.leo deleted file mode 100644 index 9e4063b297..0000000000 --- a/symbol-table/tests/symbol_table/import_undefined.leo +++ /dev/null @@ -1,5 +0,0 @@ -import foo.boo; - -function main() { - let x: u8 = boo(); -} \ No newline at end of file diff --git a/symbol-table/tests/symbol_table/imports/bar.leo b/symbol-table/tests/symbol_table/imports/bar.leo deleted file mode 100644 index 26ac259dee..0000000000 --- a/symbol-table/tests/symbol_table/imports/bar.leo +++ /dev/null @@ -1,3 +0,0 @@ -circuit Bar { - z: u32 -} \ No newline at end of file diff --git a/symbol-table/tests/symbol_table/imports/foo.leo b/symbol-table/tests/symbol_table/imports/foo.leo deleted file mode 100644 index b462c11d57..0000000000 --- a/symbol-table/tests/symbol_table/imports/foo.leo +++ /dev/null @@ -1,3 +0,0 @@ -function foo() -> u8 { - return 5u8 -} \ No newline at end of file diff --git a/symbol-table/tests/symbol_table/mod.rs b/symbol-table/tests/symbol_table/mod.rs deleted file mode 100644 index 173f610821..0000000000 --- a/symbol-table/tests/symbol_table/mod.rs +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright (C) 2019-2021 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::TestSymbolTable; - -use leo_ast::Input; -use leo_imports::ImportParser; -use leo_symbol_table::{SymbolTable, SymbolTableError}; - -/// -/// Defines a circuit `Foo {}`. -/// Attempts to define a second circuit `Foo {}`. -/// -/// Expected output: SymbolTableError -/// Message: "Duplicate circuit definition found for `Foo`." -/// -#[test] -fn test_duplicate_circuit() { - let program_string = include_str!("duplicate_circuit.leo"); - let resolver = TestSymbolTable::new(program_string); - - resolver.expect_pass_one_error(); -} - -/// -/// Defines a function `main() {}`. -/// Attempts to define a second function `main() {}`. -/// -/// Expected output: SymbolTableError -/// Message: "Duplicate function definition found for `main`." -/// -#[test] -fn test_duplicate_function() { - let program_string = include_str!("duplicate_function.leo"); - let resolver = TestSymbolTable::new(program_string); - - resolver.expect_pass_one_error(); -} - -/// -/// Defines a function that returns `Self`. -/// -/// Expected output: TypeError -/// Message: "Type `Self` is only available in circuit definitions and circuit functions." -/// -#[test] -fn test_self_not_available() { - let program_string = include_str!("self_not_available.leo"); - let resolver = TestSymbolTable::new(program_string); - - resolver.expect_pass_two_error(); -} - -/// -/// Defines a circuit with variable whose type is `Bar`, an undefined circuit. -/// -/// Expected output: TypeError -/// Message: "Type circuit `Bar` must be defined before it is used in an expression." -/// -#[test] -fn test_undefined_circuit() { - let program_string = include_str!("undefined_circuit.leo"); - let resolver = TestSymbolTable::new(program_string); - - resolver.expect_pass_two_error(); -} - -/// -/// Imports an undefined function `boo` from file foo.leo. -/// -/// Expected output: SymbolTableError -/// Message: Cannot find imported symbol `boo` in imported file `` -/// -#[test] -fn test_import_undefined() { - let program_string = include_str!("import_undefined.leo"); - let import_string = include_str!("imports/foo.leo"); - - let program_table = TestSymbolTable::new(program_string); - let import_table = TestSymbolTable::new(import_string); - - let import_program = import_table.ast.into_repr(); - - let mut imports = ImportParser::default(); - imports.insert_import("foo".to_owned(), import_program); - - // Create new symbol table. - let static_check = &mut SymbolTable::default(); - - // Run pass one and expect an error. - let error = static_check - .check_names(&program_table.ast.into_repr(), &imports, &Input::new()) - .unwrap_err(); - - match error { - SymbolTableError::Error(_) => {} // Ok - error => panic!("Expected a symbol table error found `{}`", error), - } -} - -/// -/// Imports all functions from file foo.leo. -/// Calls function `foo` defined in foo.leo. -/// -/// Expected output: Test Pass -/// -#[test] -fn test_import_star() { - let program_string = include_str!("import_star.leo"); - let import_string = include_str!("imports/foo.leo"); - - let program_table = TestSymbolTable::new(program_string); - let import_table = TestSymbolTable::new(import_string); - - let import_program = import_table.ast.into_repr(); - - let mut imports = ImportParser::default(); - imports.insert_import("foo".to_owned(), import_program); - - program_table.expect_success(imports); -} - -/// -/// Imports a circuit named `Bar` from file bar.leo. -/// Renames `Bar` => `Baz`. -/// Defines a circuit named `Bar` in main.leo. -/// Instantiates circuits `Bar` and `Baz`. -/// -/// Expected output: Test Pass -/// -#[test] -fn test_import_circuit_alias() { - let program_string = include_str!("import_circuit_alias.leo"); - let import_string = include_str!("imports/bar.leo"); - - let program_table = TestSymbolTable::new(program_string); - let import_table = TestSymbolTable::new(import_string); - - let import_program = import_table.ast.into_repr(); - - let mut imports = ImportParser::default(); - imports.insert_import("bar".to_owned(), import_program); - - program_table.expect_success(imports); -} - -/// -/// Imports a function named `foo` from file foo.leo. -/// Renames `foo` => `boo`. -/// Defines a function named `foo` in main.leo. -/// Calls functions `foo` and `boo`. -/// -/// Expected output: Test Pass -/// -#[test] -fn test_import_function_alias() { - let program_string = include_str!("import_function_alias.leo"); - let import_string = include_str!("imports/foo.leo"); - - let program_table = TestSymbolTable::new(program_string); - let import_table = TestSymbolTable::new(import_string); - - let import_program = import_table.ast.into_repr(); - - let mut imports = ImportParser::default(); - imports.insert_import("foo".to_owned(), import_program); - - program_table.expect_success(imports); -} diff --git a/symbol-table/tests/symbol_table/self_not_available.leo b/symbol-table/tests/symbol_table/self_not_available.leo deleted file mode 100644 index e34a4c5670..0000000000 --- a/symbol-table/tests/symbol_table/self_not_available.leo +++ /dev/null @@ -1,8 +0,0 @@ -/// -/// Defines a function that returns `Self`. -/// -/// Expected output: TypeError -/// Message: "Type `Self` is only available in circuit definitions and circuit functions." -/// - -function main() -> Self {} \ No newline at end of file diff --git a/symbol-table/tests/symbol_table/undefined_circuit.leo b/symbol-table/tests/symbol_table/undefined_circuit.leo deleted file mode 100644 index 396dcfd177..0000000000 --- a/symbol-table/tests/symbol_table/undefined_circuit.leo +++ /dev/null @@ -1,10 +0,0 @@ -/// -/// Defines a circuit with variable whose type is `Bar`, an undefined circuit. -/// -/// Expected output: TypeError -/// Message: "Type circuit `Bar` must be defined before it is used in an expression." -/// - -circuit Foo { - b: Bar -} \ No newline at end of file diff --git a/type-inference/Cargo.toml b/type-inference/Cargo.toml deleted file mode 100644 index d4f23b3548..0000000000 --- a/type-inference/Cargo.toml +++ /dev/null @@ -1,47 +0,0 @@ -[package] -name = "leo-type-inference" -version = "1.0.8" -authors = [ "The Aleo Team " ] -description = "Checks that a program is correct using type inference" -homepage = "https://aleo.org" -repository = "https://github.com/AleoHQ/leo" -keywords = [ - "aleo", - "cryptography", - "leo", - "programming-language", - "zero-knowledge" -] -categories = [ "cryptography::cryptocurrencies", "web-programming" ] -include = [ "Cargo.toml", "src", "README.md", "LICENSE.md" ] -license = "GPL-3.0" -edition = "2018" - -[dependencies.leo-ast] -path = "../ast" -version = "1.0.8" - -[dependencies.leo-imports] -path = "../imports" -version = "1.0.8" - -[dependencies.leo-grammar] -path = "../grammar" -version = "1.0.8" - -[dependencies.leo-symbol-table] -path = "../symbol-table" -version = "1.0.8" - -[dependencies.indexmap] -version = "1.6.1" -features = [ "serde-1" ] - -[dependencies.serde_json] -version = "1.0" - -[dependencies.serde] -version = "1.0" - -[dependencies.thiserror] -version = "1.0" diff --git a/type-inference/src/assertions/mod.rs b/type-inference/src/assertions/mod.rs deleted file mode 100644 index 46b946bc4d..0000000000 --- a/type-inference/src/assertions/mod.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (C) 2019-2021 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 . - -pub mod type_assertion; -pub use self::type_assertion::*; - -pub mod type_equality; -pub use self::type_equality::*; - -pub mod type_membership; -pub use self::type_membership::*; - -pub mod type_variable_pair; -pub use self::type_variable_pair::*; diff --git a/type-inference/src/assertions/type_assertion.rs b/type-inference/src/assertions/type_assertion.rs deleted file mode 100644 index 02bf3766fa..0000000000 --- a/type-inference/src/assertions/type_assertion.rs +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (C) 2019-2021 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::{TypeAssertionError, TypeEquality, TypeMembership, TypeVariablePairs}; -use leo_ast::Span; -use leo_symbol_table::{Type, TypeVariable}; - -use serde::{Deserialize, Serialize}; - -/// A predicate that evaluates equality between two `Types`s. -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] -pub enum TypeAssertion { - Equality(TypeEquality), - Membership(TypeMembership), -} - -impl TypeAssertion { - /// - /// Returns a `TypeAssertion::Equality` predicate from given left and right `Types`s. - /// - pub fn new_equality(left: Type, right: Type, span: &Span) -> Self { - Self::Equality(TypeEquality::new(left, right, span)) - } - - /// - /// Returns a `TypeAssertion::Membership` predicate from given and set `Type`s. - /// - pub fn new_membership(given: Type, set: Vec, span: &Span) -> Self { - Self::Membership(TypeMembership::new(given, set, span)) - } - - /// - /// Returns one or more `TypeVariablePairs` generated by the given `TypeAssertion`. - /// - pub fn pairs(&self) -> Result { - match self { - TypeAssertion::Equality(equality) => equality.pairs(), - TypeAssertion::Membership(membership) => Err(TypeAssertionError::membership_pairs(membership)), - } - } - - /// - /// Substitutes the given type for self if self is equal to the type variable. - /// - pub fn substitute(&mut self, variable: &TypeVariable, type_: &Type) { - match self { - TypeAssertion::Equality(equality) => equality.substitute(variable, type_), - TypeAssertion::Membership(membership) => membership.substitute(variable, type_), - } - } - - /// - /// Checks if the `TypeAssertion` is satisfied. - /// - pub fn evaluate(&self) -> Result<(), TypeAssertionError> { - match self { - TypeAssertion::Equality(equality) => equality.evaluate(), - TypeAssertion::Membership(membership) => membership.evaluate(), - } - } -} diff --git a/type-inference/src/assertions/type_equality.rs b/type-inference/src/assertions/type_equality.rs deleted file mode 100644 index eff73784a4..0000000000 --- a/type-inference/src/assertions/type_equality.rs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (C) 2019-2021 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::{TypeAssertionError, TypeVariablePairs}; -use leo_ast::Span; -use leo_symbol_table::{Type, TypeVariable}; - -use serde::{Deserialize, Serialize}; - -/// A predicate that evaluates equality between two `Type`s. -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] -pub struct TypeEquality { - left: Type, - right: Type, - span: Span, -} - -impl TypeEquality { - /// - /// Returns a `TypeEquality` predicate from given left and right `Types`s - /// - pub fn new(left: Type, right: Type, span: &Span) -> Self { - Self { - left, - right, - span: span.to_owned(), - } - } - - /// - /// Substitutes the given `TypeVariable` for each `Types` in the `TypeEquality`. - /// - pub fn substitute(&mut self, variable: &TypeVariable, type_: &Type) { - self.left.substitute(variable, type_); - self.right.substitute(variable, type_); - } - - /// - /// Checks if the `self.left` == `self.right`. - /// - pub fn evaluate(&self) -> Result<(), TypeAssertionError> { - if self.left.eq(&self.right) { - Ok(()) - } else { - Err(TypeAssertionError::equality_failed(&self.left, &self.right, &self.span)) - } - } - - /// - /// Returns the (type variable, type) pair from this assertion. - /// - pub fn pairs(&self) -> Result { - TypeVariablePairs::new(self.left.to_owned(), self.right.to_owned(), &self.span) - } -} diff --git a/type-inference/src/assertions/type_membership.rs b/type-inference/src/assertions/type_membership.rs deleted file mode 100644 index ab89b3661e..0000000000 --- a/type-inference/src/assertions/type_membership.rs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (C) 2019-2021 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::TypeAssertionError; -use leo_ast::Span; -use leo_symbol_table::{Type, TypeVariable}; - -use serde::{Deserialize, Serialize}; - -/// A predicate that evaluates to true if the given type is equal to a member in the set vector of types. -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] -pub struct TypeMembership { - given: Type, - set: Vec, - span: Span, -} - -impl TypeMembership { - /// - /// Returns a `TypeMembership` predicate from given and set `Type`s. - /// - pub fn new(given: Type, set: Vec, span: &Span) -> Self { - Self { - given, - set, - span: span.to_owned(), - } - } - - /// - /// Substitutes the given `TypeVariable` for each `Type` in the `TypeMembership`. - /// - pub fn substitute(&mut self, variable: &TypeVariable, type_: &Type) { - self.given.substitute(variable, type_) - } - - /// - /// Returns true if the given type is equal to a member of the set. - /// - pub fn evaluate(&self) -> Result<(), TypeAssertionError> { - if self.set.contains(&self.given) { - Ok(()) - } else { - Err(TypeAssertionError::membership_failed( - &self.given, - &self.set, - &self.span, - )) - } - } - - /// - /// Returns the self.span. - /// - pub fn span(&self) -> &Span { - &self.span - } -} diff --git a/type-inference/src/assertions/type_variable_pair.rs b/type-inference/src/assertions/type_variable_pair.rs deleted file mode 100644 index 3e6111ab73..0000000000 --- a/type-inference/src/assertions/type_variable_pair.rs +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright (C) 2019-2021 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::TypeAssertionError; -use leo_ast::Span; -use leo_symbol_table::{get_array_element_type, Type, TypeVariable}; - -/// A type variable -> type pair. -pub struct TypeVariablePair(TypeVariable, Type); - -impl TypeVariablePair { - pub fn first(&self) -> &TypeVariable { - &self.0 - } - - pub fn second(&self) -> &Type { - &self.1 - } -} - -/// A vector of `TypeVariablePair`s. -pub struct TypeVariablePairs(Vec); - -impl Default for TypeVariablePairs { - fn default() -> Self { - Self(Vec::new()) - } -} - -impl TypeVariablePairs { - /// - /// Returns a new `TypeVariablePairs` struct from the given left and right types. - /// - pub fn new(left: Type, right: Type, span: &Span) -> Result { - let mut pairs = Self::default(); - - // Push all `TypeVariablePair`s. - pairs.push_pairs(left, right, span)?; - - Ok(pairs) - } - - /// - /// Returns true if the self vector has no pairs. - /// - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } - - /// - /// Returns the self vector of pairs. - /// - pub fn get_pairs(&self) -> &[TypeVariablePair] { - &self.0 - } - - /// - /// Pushes a new `TypeVariablePair` struct to self. - /// - pub fn push(&mut self, variable: TypeVariable, type_: Type) { - // Create a new type variable -> type pair. - let pair = TypeVariablePair(variable, type_); - - // Push the pair to the self vector. - self.0.push(pair); - } - - /// - /// Checks if the given left or right type contains a `TypeVariable`. - /// If a `TypeVariable` is found, create a new `TypeVariablePair` between the given left - /// and right type. - /// - pub fn push_pairs(&mut self, left: Type, right: Type, span: &Span) -> Result<(), TypeAssertionError> { - match (left, right) { - (Type::TypeVariable(variable), type_) => { - self.push(variable, type_); - Ok(()) - } - (type_, Type::TypeVariable(variable)) => { - self.push(variable, type_); - Ok(()) - } - (Type::Array(left_type), Type::Array(right_type)) => self.push_pairs_array(*left_type, *right_type, span), - (Type::Tuple(left_types), Type::Tuple(right_types)) => { - self.push_pairs_tuple(left_types.into_iter(), right_types.into_iter(), span) - } - (_, _) => Ok(()), // No `TypeVariable` found so we do not push any pairs. - } - } - - /// - /// Checks if the given left or right array type contains a `TypeVariable`. - /// If a `TypeVariable` is found, create a new `TypeVariablePair` between the given left - /// and right type. - /// - fn push_pairs_array(&mut self, left_type: Type, right_type: Type, span: &Span) -> Result<(), TypeAssertionError> { - // Get both array element types before comparison. - let array1_element = get_array_element_type(&left_type); - let array2_element = get_array_element_type(&right_type); - - // Compare the array element types. - self.push_pairs(array1_element.to_owned(), array2_element.to_owned(), span) - } - - /// - /// Checks if any given left or right tuple type contains a `TypeVariable`. - /// If a `TypeVariable` is found, create a new `TypeVariablePair` between the given left - /// and right type. - /// - fn push_pairs_tuple( - &mut self, - left_types: impl Iterator, - right_types: impl Iterator, - span: &Span, - ) -> Result<(), TypeAssertionError> { - // Iterate over each left == right pair of types. - for (left, right) in left_types.into_iter().zip(right_types) { - // Check for `TypeVariablePair`s. - self.push_pairs(left, right, span)?; - } - - Ok(()) - } -} diff --git a/type-inference/src/errors/frame.rs b/type-inference/src/errors/frame.rs deleted file mode 100644 index 55487f0dc9..0000000000 --- a/type-inference/src/errors/frame.rs +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright (C) 2019-2021 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::{ScopeError, TypeAssertionError}; -use leo_ast::{Error as FormattedError, Expression, Identifier, Span}; -use leo_symbol_table::{Type, TypeError}; - -use std::path::Path; - -/// Errors encountered when tracking variable names in a program. -#[derive(Debug, Error)] -pub enum FrameError { - #[error("{}", _0)] - Error(#[from] FormattedError), - - #[error("{}", _0)] - ScopeError(#[from] ScopeError), - - #[error("{}", _0)] - TypeAssertionError(#[from] TypeAssertionError), - - #[error("{}", _0)] - TypeError(#[from] TypeError), -} - -impl FrameError { - /// - /// Set the filepath for the error stacktrace - /// - pub fn set_path(&mut self, path: &Path) { - match self { - FrameError::Error(error) => error.set_path(path), - FrameError::ScopeError(error) => error.set_path(path), - FrameError::TypeAssertionError(error) => error.set_path(path), - FrameError::TypeError(error) => error.set_path(path), - } - } - - /// - /// Return a new formatted error with a given message and span information - /// - fn new_from_span(message: String, span: &Span) -> Self { - FrameError::Error(FormattedError::new_from_span(message, span.to_owned())) - } - - /// - /// Attempted to access the index of a non-array type. - /// - pub fn array_access(actual: &Type, span: &Span) -> Self { - let message = format!("Cannot access the index of non-array type `{}`.", actual); - - Self::new_from_span(message, span) - } - - /// - /// Attempted to access the `Self` type outside of a circuit context. - /// - pub fn circuit_self(span: &Span) -> Self { - let message = "The `Self` keyword is only valid inside a circuit context.".to_string(); - - Self::new_from_span(message, span) - } - - /// - /// Two variables have been defined with the same name. - /// - pub fn duplicate_variable(name: &str, span: &Span) -> Self { - let message = format!("Duplicate variable definition found for `{}`", name); - - Self::new_from_span(message, span) - } - - /// - /// Attempted to create an empty array in a Leo program. - /// - /// Arrays in Leo are not resizeable so defining empty arrays are effectively dead code. - /// - pub fn empty_array(span: &Span) -> Self { - let message = "Cannot create an empty array in a Leo program.".to_string(); - - Self::new_from_span(message, span) - } - - /// - /// Expected a circuit name but found a different type. - /// - pub fn invalid_circuit(type_: Type, span: &Span) -> Self { - let message = format!("Expected a circuit type. Found type `{}`.", type_); - - Self::new_from_span(message, span) - } - - /// - /// Expected a function name but found a different expression. - /// - pub fn invalid_function(expression: &Expression, span: &Span) -> Self { - let message = format!("Expected a function name. Found expression `{}`.", expression); - - Self::new_from_span(message, span) - } - - /// - /// Expected a usize number for the index. - /// - pub fn invalid_index(actual: String, span: &Span) -> Self { - let message = format!("Expected constant number for index, found `{}`", actual); - - Self::new_from_span(message, span) - } - - /// - /// Attempted to call non-static member using `::`. - /// - pub fn invalid_member_access(identifier: &Identifier) -> Self { - let message = format!("non-static member `{}` must be accessed using `.` syntax.", identifier); - - Self::new_from_span(message, &identifier.span) - } - - /// - /// Attempted to use the spread operator on a non-array type. - /// - pub fn invalid_spread(actual: Type, span: &Span) -> Self { - let message = format!( - "The spread operator `...` can only be applied to array types. Found type `{}`.", - actual - ); - - Self::new_from_span(message, span) - } - - /// - /// Attempted to call static member using `.`. - /// - pub fn invalid_static_access(identifier: &Identifier) -> Self { - let message = format!("Static member `{}` must be accessed using `::` syntax.", identifier); - - Self::new_from_span(message, &identifier.span) - } - - /// - /// Attempted to create a circuit with the incorrect number of member variables. - /// - pub fn num_circuit_variables(expected: usize, actual: usize, span: &Span) -> Self { - let message = format!("Circuit expected {} variables, found {} variables.", expected, actual); - - Self::new_from_span(message, span) - } - - /// - /// Attempted to call a function with the incorrect number of inputs. - /// - pub fn num_inputs(expected: usize, actual: usize, span: &Span) -> Self { - let message = format!( - "Function expected {} input variables, found {} inputs.", - expected, actual - ); - - Self::new_from_span(message, span) - } - - /// - /// The `self` keyword was used in a static circuit function signature. - /// - pub fn self_not_available(span: &Span) -> Self { - let message = "keyword `self` is only available in static circuit functions.".to_string(); - - Self::new_from_span(message, span) - } - - /// - /// A static function was accessed using dot `.` syntax instead of double colon `::` syntax. - /// - pub fn static_call_invalid(identifier: &Identifier) -> Self { - let message = format!( - "Static function `{}` must be called using double colon `::` syntax.", - identifier.name - ); - - Self::new_from_span(message, &identifier.span) - } - - /// - /// Attempted to access the index of a non-tuple type. - /// - pub fn tuple_access(actual: &Type, span: &Span) -> Self { - let message = format!("Cannot access the index of non-tuple type `{}`.", actual); - - Self::new_from_span(message, span) - } - - /// - /// Attempted to call a circuit type that is not defined in the current context. - /// - pub fn undefined_circuit(identifier: &Identifier) -> Self { - let message = format!("The circuit `{}` is not defined.", identifier); - - Self::new_from_span(message, &identifier.span) - } - - /// - /// Attempted to call a circuit function that is not defined in the current context. - /// - pub fn undefined_circuit_function(identifier: &Identifier) -> Self { - let message = format!("The circuit function `{}` is not defined.", identifier); - - Self::new_from_span(message, &identifier.span) - } - - /// - /// Attempted to call a function that is not defined in the current context. - /// - pub fn undefined_function(identifier: &Identifier) -> Self { - let message = format!("The function `{}` is not defined.", identifier); - - Self::new_from_span(message, &identifier.span) - } - - /// - /// Attempted to call a variable that is not defined in the current context. - /// - pub fn undefined_variable(identifier: &Identifier) -> Self { - let message = format!("The variable `{}` is not defined.", identifier); - - Self::new_from_span(message, &identifier.span) - } - - /// - /// Attempted to assign a tuple of variables to a single value. - /// - pub fn not_enough_values(span: &Span) -> Self { - let message = "Expected a tuple type for multiple defined variables".to_string(); - - Self::new_from_span(message, span) - } - - /// - /// Attempted to assign a tuple with a different number of variables than values. - /// - pub fn invalid_number_of_values(expected: usize, actual: usize, span: &Span) -> Self { - let message = format!( - "Incorrect number of defined variables. Expected `{}`, found `{}`.", - expected, actual - ); - - Self::new_from_span(message, span) - } -} diff --git a/type-inference/src/errors/mod.rs b/type-inference/src/errors/mod.rs deleted file mode 100644 index a6ececc3fa..0000000000 --- a/type-inference/src/errors/mod.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (C) 2019-2021 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 . - -pub mod frame; -pub use self::frame::*; - -pub mod scope; -pub use self::scope::*; - -pub mod type_assertion; -pub use self::type_assertion::*; - -pub mod type_inference; -pub use self::type_inference::*; - -pub mod variable_table; -pub use self::variable_table::*; diff --git a/type-inference/src/errors/scope.rs b/type-inference/src/errors/scope.rs deleted file mode 100644 index 91c0108770..0000000000 --- a/type-inference/src/errors/scope.rs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (C) 2019-2021 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::VariableTableError; -use leo_ast::Error as FormattedError; - -use std::path::Path; - -/// Errors encountered when evaluating variables in a scope. -#[derive(Debug, Error)] -pub enum ScopeError { - #[error("{}", _0)] - Error(#[from] FormattedError), - - #[error("{}", _0)] - VariableTableError(#[from] VariableTableError), -} - -impl ScopeError { - /// - /// Set the filepath for the error stacktrace. - /// - pub fn set_path(&mut self, path: &Path) { - match self { - ScopeError::Error(error) => error.set_path(path), - ScopeError::VariableTableError(error) => error.set_path(path), - } - } -} diff --git a/type-inference/src/errors/type_assertion.rs b/type-inference/src/errors/type_assertion.rs deleted file mode 100644 index 0096150e28..0000000000 --- a/type-inference/src/errors/type_assertion.rs +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (C) 2019-2021 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::TypeMembership; - -use leo_ast::{Error as FormattedError, Span}; -use leo_symbol_table::Type; - -use std::path::Path; - -/// Errors encountered when attempting to solve a type assertion. -#[derive(Debug, Error)] -pub enum TypeAssertionError { - #[error("{}", _0)] - Error(#[from] FormattedError), -} - -impl TypeAssertionError { - /// - /// Set the filepath for the error stacktrace. - /// - pub fn set_path(&mut self, path: &Path) { - match self { - TypeAssertionError::Error(error) => error.set_path(path), - } - } - - /// - /// Returns a new formatted error with a given message and span information. - /// - fn new_from_span(message: String, span: &Span) -> Self { - TypeAssertionError::Error(FormattedError::new_from_span(message, span.to_owned())) - } - - /// - /// Found mismatched types during program parsing. - /// - pub fn equality_failed(left: &Type, right: &Type, span: &Span) -> Self { - let message = format!("Mismatched types. Expected type `{}`, found type `{}`.", left, right); - - Self::new_from_span(message, span) - } - - /// - /// Given type is not a member of the set of expected types. - /// - pub fn membership_failed(given: &Type, set: &[Type], span: &Span) -> Self { - let message = format!( - "Mismatched types. Given type `{}` is not in the expected type set `{:?}`.", - given, set - ); - - Self::new_from_span(message, span) - } - - /// - /// Attempted to generate pairs from a membership assertion. - /// - pub fn membership_pairs(membership: &TypeMembership) -> Self { - let message = "Cannot generate a type variable -> type pair for the given type membership".to_string(); - - Self::new_from_span(message, membership.span()) - } -} diff --git a/type-inference/src/errors/type_inference.rs b/type-inference/src/errors/type_inference.rs deleted file mode 100644 index 73f96dd4db..0000000000 --- a/type-inference/src/errors/type_inference.rs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (C) 2019-2021 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::FrameError; -use leo_ast::Error as FormattedError; - -use std::path::Path; - -/// Errors encountered when running type inference checks. -#[derive(Debug, Error)] -pub enum TypeInferenceError { - #[error("{}", _0)] - Error(#[from] FormattedError), - - #[error("{}", _0)] - FrameError(#[from] FrameError), -} - -impl TypeInferenceError { - /// - /// Set the filepath for the error stacktrace. - /// - pub fn set_path(&mut self, path: &Path) { - match self { - TypeInferenceError::Error(error) => error.set_path(path), - TypeInferenceError::FrameError(error) => error.set_path(path), - } - } -} diff --git a/type-inference/src/errors/variable_table.rs b/type-inference/src/errors/variable_table.rs deleted file mode 100644 index 59c9272f9d..0000000000 --- a/type-inference/src/errors/variable_table.rs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (C) 2019-2021 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 leo_ast::{Error as FormattedError, Span}; - -use std::path::Path; - -/// Errors encountered when tracking variable names in a program. -#[derive(Debug, Error)] -pub enum VariableTableError { - #[error("{}", _0)] - Error(#[from] FormattedError), -} - -impl VariableTableError { - /// - /// Set the filepath for the error stacktrace - /// - pub fn set_path(&mut self, path: &Path) { - match self { - VariableTableError::Error(error) => error.set_path(path), - } - } - - /// - /// Return a new formatted error with a given message and span information - /// - fn new_from_span(message: String, span: Span) -> Self { - VariableTableError::Error(FormattedError::new_from_span(message, span)) - } - - /// - /// Attempted to define two function inputs with the same name. - /// - pub fn duplicate_function_input(name: &str, span: &Span) -> Self { - let message = format!("Duplicate function input `{}`found in function signature.", name); - - Self::new_from_span(message, span.clone()) - } -} diff --git a/type-inference/src/lib.rs b/type-inference/src/lib.rs deleted file mode 100644 index 97d81ce99c..0000000000 --- a/type-inference/src/lib.rs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (C) 2019-2021 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 . - -//! A type inference check for a Leo program. -//! -//! This module contains the [`TypeInference`] type, which stores information needed to run a type -//! inference check over a program. -//! -//! A new [`TypeInference`] type can be created from a [`LeoAst`] type and a [`Symbol Table`]. - -#[macro_use] -extern crate thiserror; - -pub mod assertions; -pub use self::assertions::*; - -pub mod type_inference; -pub use self::type_inference::*; - -pub mod errors; -pub use self::errors::*; - -pub mod objects; -pub use self::objects::*; diff --git a/type-inference/src/objects/frame.rs b/type-inference/src/objects/frame.rs deleted file mode 100644 index acdefb89c0..0000000000 --- a/type-inference/src/objects/frame.rs +++ /dev/null @@ -1,1166 +0,0 @@ -// Copyright (C) 2019-2021 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::{FrameError, Scope, TypeAssertion}; -use leo_ast::{ - expression::*, - statements::*, - ArrayDimensions, - Assignee, - AssigneeAccess, - Block, - CircuitVariableDefinition, - Expression, - Function, - Identifier, - IntegerType, - PositiveNumber, - Span, - SpreadOrExpression, -}; -use leo_symbol_table::{CircuitType, FunctionType, SymbolTable, Type, TypeVariable}; - -/// A vector of `TypeAssertion` predicates created from a function body. -#[derive(Clone)] -pub struct Frame { - pub function_type: FunctionType, - pub self_type: Option, - pub scopes: Vec, - pub block: Block, - pub type_assertions: Vec, - pub user_defined_types: SymbolTable, -} - -impl Frame { - /// - /// Collects a vector of `TypeAssertion` predicates from a function. - /// - pub fn new_function( - function: Function, - self_type: Option, - parent_scope: Option, - user_defined_types: SymbolTable, - ) -> Result { - let name = &function.identifier.name; - - // Get function type from symbol table. - let function_type = user_defined_types.get_function_type(name).unwrap().clone(); - - // Create a new scope for the function variables. - let mut scope = Scope::new(parent_scope); - - // Initialize function inputs as variables. - scope.insert_function_inputs(&function_type.inputs)?; - - // Create new list of scopes for frame. - let scopes = vec![scope]; - - // Create new frame struct. - // Update variables when encountering let/const variable definitions. - let mut frame = Self { - function_type, - self_type, - scopes, - block: function.block, - type_assertions: vec![], - user_defined_types, - }; - - // Create type assertions for function statements - frame.parse_statements()?; - - Ok(frame) - } - - /// - /// Collects vector of `TypeAssertion` predicates from a circuit function. - /// - pub fn new_circuit_function( - function: Function, - self_type: CircuitType, - parent_scope: Scope, - user_defined_types: SymbolTable, - ) -> Result { - let identifier = &function.identifier; - - // Find function name in circuit members. - let function_type = self_type.member_function_type(identifier).unwrap().to_owned(); - - // Create a new scope for the function variables. - let mut scope = Scope::new(Some(parent_scope)); - - // Initialize function inputs as variables. - scope.insert_function_inputs(&function_type.inputs)?; - - // Create new list of scopes for frame. - let scopes = vec![scope]; - - // Create new frame struct. - // Update variables when encountering let/const variable definitions. - let mut frame = Self { - function_type, - self_type: Some(self_type), - scopes, - block: function.block, - type_assertions: Vec::new(), - user_defined_types, - }; - - // Create type assertions for function statements - frame.parse_statements()?; - - Ok(frame) - } - - /// - /// Pushes a new variable `Scope` to the list of scopes in the current `Frame`. - /// - fn push_scope(&mut self, scope: Scope) { - self.scopes.push(scope) - } - - /// - /// Removes and returns the most recent `Scope` from the list of scopes in the current `Frame`. - /// - fn pop_scope(&mut self) -> Option { - self.scopes.pop() - } - - /// - /// Insert a variable into the symbol table in the current scope. - /// - fn insert_variable(&mut self, name: String, type_: Type, span: &Span) -> Result<(), FrameError> { - // Modify the current scope. - let scope = self.scopes.last_mut().unwrap(); - - // Insert the variable name -> type. - match scope.variables.insert(name.clone(), type_) { - Some(_type) => Err(FrameError::duplicate_variable(&name, span)), - None => Ok(()), - } - } - - /// - /// Get a variable's type from the symbol table in the current scope. - /// - fn get_variable(&self, name: &str) -> Option<&Type> { - // Lookup in the current scope. - let scope = self.scopes.last().unwrap(); - - // Get the variable by name. - scope.get_variable(name) - } - - /// - /// Get a function's type from the user defined types in the current scope. - /// - fn get_function(&self, name: &str) -> Option<&FunctionType> { - self.user_defined_types.get_function_type(name) - } - - /// - /// Get a circuit's type from the user defined types in the current scope. - /// - fn get_circuit(&self, name: &str) -> Option<&CircuitType> { - self.user_defined_types.get_circuit_type(name) - } - - /// - /// Creates a new equality type assertion between the given types. - /// - fn assert_equal(&mut self, left: Type, right: Type, span: &Span) { - let type_assertion = TypeAssertion::new_equality(left, right, span); - - self.type_assertions.push(type_assertion); - } - - /// - /// Creates a new membership type assertion between a given and set of types. - /// - fn assert_membership(&mut self, given: Type, set: Vec, span: &Span) { - let type_assertion = TypeAssertion::new_membership(given, set, span); - - self.type_assertions.push(type_assertion); - } - - /// - /// Creates a new membership type assertion between a given and the set of negative integer types. - /// - fn assert_negative_integer(&mut self, given: &Type, span: &Span) { - let negative_integer_types = Type::negative_integer_types(); - - self.assert_membership(given.clone(), negative_integer_types, span) - } - - /// - /// Creates a new membership type assertion between a given and the set of all integer types. - /// - fn assert_integer(&mut self, given: &Type, span: &Span) { - let integer_types = Type::integer_types(); - - self.assert_membership(given.clone(), integer_types, span) - } - - /// - /// Creates a new membership type assertion between a given and the set of index types. - /// - fn assert_index(&mut self, given: &Type, span: &Span) { - let index_types = Type::index_types(); - - self.assert_membership(given.clone(), index_types, span) - } - - /// - /// Collects a vector of `TypeAssertion` predicates from a vector of statements. - /// - fn parse_statements(&mut self) -> Result<(), FrameError> { - for statement in self.block.statements.clone() { - self.parse_statement(&statement)?; - } - - Ok(()) - } - - /// - /// Collects a vector of `TypeAssertion` predicates from a statement. - /// - fn parse_statement(&mut self, statement: &Statement) -> Result<(), FrameError> { - match statement { - Statement::Return(statement) => self.parse_return(statement), - Statement::Definition(statement) => self.parse_definition(statement), - Statement::Assign(statement) => self.parse_assign(statement), - Statement::Conditional(statement) => self.parse_statement_conditional(statement), - Statement::Iteration(statement) => self.parse_iteration(statement), - Statement::Expression(statement) => self.parse_statement_expression(statement), - Statement::Console(_console_call) => Ok(()), // Console function calls do not generate type assertions. - Statement::Block(statement) => self.parse_block(statement), - } - } - - /// - /// Collects `TypeAssertion` predicates from a return statement. - /// - fn parse_return(&mut self, statement: &ReturnStatement) -> Result<(), FrameError> { - // Get the function output type. - let output_type = &self.function_type.output.type_; - - // Create the left hand side of a type assertion. - let left = output_type.clone(); - - // Create the right hand side from the statement return expression. - let right = self.parse_expression(&statement.expression)?; - - // Create a new type assertion for the statement return. - self.assert_equal(left, right, &statement.span); - - Ok(()) - } - - /// - /// Collects `Type Assertion` predicates from a definition statement. - /// - fn parse_definition(&mut self, statement: &DefinitionStatement) -> Result<(), FrameError> { - // Parse the definition expression. - let actual_type = self.parse_expression(&statement.value)?; - - // Check if an explicit type is given. - if let Some(type_) = statement.type_.clone() { - // Check the expected type. - let expected_type = match self.self_type { - Some(ref circuit_type) => Type::new_from_circuit( - &self.user_defined_types, - type_, - circuit_type.identifier.clone(), - statement.span.clone(), - ) - .unwrap(), - None => Type::new(&self.user_defined_types, type_, statement.span.clone()).unwrap(), - }; - - // Assert that the expected type is equal to the actual type. - self.assert_equal(expected_type, actual_type.clone(), &statement.span) - } - - // Check for multiple defined variables. - if statement.variable_names.len() == 1 { - // Insert variable into symbol table - let variable = statement.variable_names[0].clone(); - self.insert_variable(variable.identifier.name, actual_type, &statement.span)?; - } else { - // Expect a tuple type. - let types = match actual_type { - Type::Tuple(types) => types, - _ => return Err(FrameError::not_enough_values(&statement.span)), - }; - - // Check number of variables == number of types. - if types.len() != statement.variable_names.len() { - return Err(FrameError::invalid_number_of_values( - types.len(), - statement.variable_names.len(), - &statement.span, - )); - } - - // Insert variables into symbol table - for (variable, type_) in statement.variable_names.iter().zip(types) { - self.insert_variable(variable.identifier.name.clone(), type_, &statement.span)?; - } - } - - Ok(()) - } - - /// - /// Asserts that the assignee's type is equal to the `Expression` type. - /// - fn parse_assign(&mut self, statement: &AssignStatement) -> Result<(), FrameError> { - // Parse assignee type. - let assignee_type = self.parse_assignee(&statement.assignee, &statement.span)?; - - // Parse expression type. - let expression_type = self.parse_expression(&statement.value)?; - - // Assert that the assignee_type == expression_type. - self.assert_equal(assignee_type, expression_type, &statement.span); - - Ok(()) - } - - /// - /// Returns the type of the assignee. - /// - fn parse_assignee(&mut self, assignee: &Assignee, span: &Span) -> Result { - // Get the type of the assignee variable. - let mut type_ = if assignee.identifier.is_self() { - // If the variable is the self keyword, then return the self.circuit_type - let self_type = self.self_type_or_error(span)?; - - Type::Circuit(self_type.identifier) - } else { - // Otherwise, lookup the variable by name in the symbol table. - self.get_variable(&assignee.identifier.name) - .map(|type_| type_.to_owned()) - .ok_or_else(|| FrameError::undefined_variable(&assignee.identifier))? - }; - - // Iteratively evaluate assignee access types. - for access in &assignee.accesses { - let access_type = match access { - AssigneeAccess::ArrayIndex(index) => self.parse_array_access(type_, index, span), - AssigneeAccess::ArrayRange(left, right) => { - self.parse_array_range_access(type_, left.as_ref(), right.as_ref(), span) - } - AssigneeAccess::Tuple(index, _) => self.parse_tuple_access(type_, &index, span), - AssigneeAccess::Member(identifier) => self.parse_circuit_member_access(type_, identifier, span), - }?; - - type_ = access_type; - } - - Ok(type_) - } - - /// - /// Collects `TypeAssertion` predicates from a block of statements. - /// - fn parse_block(&mut self, block: &Block) -> Result<(), FrameError> { - // Push new scope. - let scope = Scope::new(self.scopes.last().cloned()); - self.push_scope(scope); - - // Parse all statements. - for statement in &block.statements { - self.parse_statement(&statement)?; - } - - // Pop out of scope. - let _scope = self.pop_scope(); - - Ok(()) - } - - /// - /// Collects `TypeAssertion` predicates from a conditional statement. - /// - /// Creates a new scope for each code block in the conditional. - /// - fn parse_statement_conditional(&mut self, conditional: &ConditionalStatement) -> Result<(), FrameError> { - // Parse the condition expression. - let condition = self.parse_expression(&conditional.condition)?; - - // Assert that the condition is a boolean type. - let boolean_type = Type::Boolean; - self.assert_equal(boolean_type, condition, &conditional.span); - - // Parse conditional statements. - self.parse_block(&conditional.block)?; - - // Parse conditional or end. - if let Some(cond_or_end) = &conditional.next { - self.parse_statement(cond_or_end)?; - } - - Ok(()) - } - - /// - /// Collects `TypeAssertion` predicates from an iteration statement. - /// - fn parse_iteration(&mut self, statement: &IterationStatement) -> Result<(), FrameError> { - // Insert variable into symbol table with u32 type. - let u32_type = Type::IntegerType(IntegerType::U32); - let _expect_none = self.insert_variable(statement.variable.name.to_owned(), u32_type.clone(), &statement.span); - - // Parse `from` and `to` expressions. - let from_type = self.parse_index(&statement.start)?; - let to_type = self.parse_index(&statement.stop)?; - - // Assert `from` and `to` types are a u32 or implicit. - self.assert_equal(u32_type.clone(), from_type, &statement.span); - self.assert_equal(u32_type, to_type, &statement.span); - - // Parse block of statements. - self.parse_block(&statement.block) - } - - /// - /// Asserts that the statement `UnresolvedExpression` returns an empty tuple. - /// - fn parse_statement_expression(&mut self, statement: &ExpressionStatement) -> Result<(), FrameError> { - // Create empty tuple type. - let expected_type = Type::Tuple(Vec::new()); - - // Parse the actual type of the expression. - let actual_type = self.parse_expression(&statement.expression)?; - - self.assert_equal(expected_type, actual_type, &statement.span); - - Ok(()) - } - - /// - /// Returns the type of an expression. - /// - fn parse_expression(&mut self, expression: &Expression) -> Result { - use Expression::*; - match expression { - // Type variables - Identifier(identifier) => self.parse_identifier(identifier), - - // Explicit types - Value(ValueExpression::Boolean(_, _)) => Ok(Type::Boolean), - Value(ValueExpression::Address(_, _)) => Ok(Type::Address), - Value(ValueExpression::Field(_, _)) => Ok(Type::Field), - Value(ValueExpression::Group(_)) => Ok(Type::Group), - Value(ValueExpression::Implicit(name, span)) => { - Ok(Self::parse_implicit(leo_ast::Identifier::new_with_span(name, span))) - } - Value(ValueExpression::Integer(integer_type, _, _)) => Ok(Type::IntegerType(integer_type.clone())), - - Binary(binary) => match binary.op.class() { - BinaryOperationClass::Numeric => { - self.parse_integer_binary_expression(&binary.left, &binary.right, &binary.span) - } - BinaryOperationClass::Boolean => { - self.parse_boolean_binary_expression(&binary.left, &binary.right, &binary.span) - } - }, - Unary(unary) => match &unary.op { - UnaryOperation::Negate => self.parse_negate_expression(&unary.inner, &unary.span), - UnaryOperation::Not => self.parse_boolean_expression(&unary.inner, &unary.span), - }, - - Ternary(conditional) => self.parse_conditional_expression( - &conditional.condition, - &conditional.if_true, - &conditional.if_false, - &conditional.span, - ), - - ArrayInline(array_inline) => self.parse_array(&array_inline.elements, &array_inline.span), - ArrayInit(array_init) => { - self.parse_array_initializer(&array_init.element, &array_init.dimensions, &array_init.span) - } - ArrayAccess(array_access) => { - let array_type = self.parse_expression(&array_access.array)?; - self.parse_array_access(array_type, &array_access.index, &array_access.span) - } - ArrayRangeAccess(array_range_access) => { - let array_type = self.parse_expression(&array_range_access.array)?; - self.parse_array_range_access( - array_type, - array_range_access.left.as_deref(), - array_range_access.right.as_deref(), - &array_range_access.span, - ) - } - - TupleInit(tuple_init) => self.parse_tuple(&tuple_init.elements, &tuple_init.span), - TupleAccess(tuple_access) => { - self.parse_expression_tuple_access(&tuple_access.tuple, &tuple_access.index, &tuple_access.span) - } - - CircuitInit(circuit_init) => { - self.parse_circuit(&circuit_init.name, &circuit_init.members, &circuit_init.span) - } - CircuitMemberAccess(circuit_member_access) => self.parse_expression_circuit_member_access( - &circuit_member_access.circuit, - &circuit_member_access.name, - &circuit_member_access.span, - ), - CircuitStaticFunctionAccess(circuit_static_function_access) => self.parse_static_circuit_function_access( - &circuit_static_function_access.circuit, - &circuit_static_function_access.name, - &circuit_static_function_access.span, - ), - - Call(call) => self.parse_function_call(&call.function, &call.arguments, &call.span), - } - } - - /// - /// Returns the type of the identifier in the symbol table. - /// - fn parse_identifier(&self, identifier: &Identifier) -> Result { - // Check Self type. - if identifier.is_self() { - // Check for frame circuit self type. - let circuit_type = self.self_type_or_error(&identifier.span)?; - - // Return new type with circuit identifier. - return Ok(Type::Circuit(circuit_type.identifier)); - } - - // Check variable symbol table. - if let Some(type_) = self.get_variable(&identifier.name) { - return Ok(type_.to_owned()); - }; - - // Check function symbol table. - if let Some(function_type) = self.get_function(&identifier.name) { - return Ok(Type::Function(function_type.identifier.to_owned())); - }; - - // Check circuit symbol table. - if let Some(circuit_type) = self.get_circuit(&identifier.name) { - return Ok(Type::Circuit(circuit_type.identifier.to_owned())); - } - - Ok(Self::parse_implicit(identifier.to_owned())) - } - - /// - /// Returns a new type variable from a given identifier - /// - fn parse_implicit(identifier: Identifier) -> Type { - Type::TypeVariable(TypeVariable::from(identifier)) - } - - /// - /// Returns the type of a binary expression. - /// - fn parse_binary_expression( - &mut self, - left: &Expression, - right: &Expression, - span: &Span, - ) -> Result { - // Get the left expression type. - let left_type = self.parse_expression(left)?; - - // Get the right expression type. - let right_type = self.parse_expression(right)?; - - // Create a type assertion left_type == right_type. - self.assert_equal(left_type.clone(), right_type, span); - - Ok(left_type) - } - - /// - /// Returns the `Type` of the expression after the binary operation. - /// - /// Asserts that the `Type` is an integer. - /// - fn parse_integer_binary_expression( - &mut self, - left: &Expression, - right: &Expression, - span: &Span, - ) -> Result { - let type_ = self.parse_binary_expression(left, right, span)?; - - // Assert that the type is an integer. - self.assert_integer(&type_, span); - - Ok(type_) - } - - /// - /// Returns the `Boolean` type if the expression is a `Boolean` type. - /// - fn parse_boolean_expression(&mut self, expression: &Expression, span: &Span) -> Result { - // Return the `Boolean` type - let boolean_type = Type::Boolean; - - // Get the type of the expression - let expression_type = self.parse_expression(expression)?; - - // Assert that the type is a boolean. - self.assert_equal(boolean_type.clone(), expression_type, span); - - Ok(boolean_type) - } - - /// - /// Returns the `Type` of the expression being negated. Must be a negative integer type. - /// - fn parse_negate_expression(&mut self, expression: &Expression, span: &Span) -> Result { - // Parse the expression type. - let type_ = self.parse_expression(expression)?; - - // Assert that this integer can be negated. - self.assert_negative_integer(&type_, span); - - Ok(type_) - } - - /// - /// Returns the `Boolean` type if the binary expression is a `Boolean` type. - /// - fn parse_boolean_binary_expression( - &mut self, - left: &Expression, - right: &Expression, - span: &Span, - ) -> Result { - // Create the `Boolean` type. - let boolean_type = Type::Boolean; - - // Create a new type assertion for the binary expression - let _binary_expression_type = self.parse_binary_expression(left, right, span)?; - - // Return the `Boolean` type. - Ok(boolean_type) - } - - /// - /// Returns the type of the conditional expression. - /// - fn parse_conditional_expression( - &mut self, - condition: &Expression, - first: &Expression, - second: &Expression, - span: &Span, - ) -> Result { - // Check that the type of the condition expression is a boolean. - let _condition_type = self.parse_boolean_expression(condition, span)?; - - // Check that the types of the first and second expression are equal. - self.parse_binary_expression(first, second, span) - } - - /// - /// Returns the type of the tuple expression. - /// - fn parse_tuple(&mut self, expressions: &[Expression], _span: &Span) -> Result { - let mut types = Vec::with_capacity(expressions.len()); - - // Parse all tuple expressions. - for expression in expressions { - let type_ = self.parse_expression(expression)?; - - types.push(type_) - } - - Ok(Type::Tuple(types)) - } - - /// - /// Returns the type of the accessed tuple element when called as an expression. - /// - fn parse_expression_tuple_access( - &mut self, - expression: &Expression, - index: &PositiveNumber, - span: &Span, - ) -> Result { - // Parse the tuple expression which could be a variable with type tuple. - let type_ = self.parse_expression(expression)?; - - // Parse the tuple access. - self.parse_tuple_access(type_, index, span) - } - - /// - /// Returns the type of the accessed tuple element. - /// - fn parse_tuple_access(&mut self, type_: Type, index: &PositiveNumber, span: &Span) -> Result { - // Check the type is a tuple. - let mut elements = match type_ { - Type::Tuple(elements) => elements, - type_ => return Err(FrameError::tuple_access(&type_, span)), - }; - - // Parse index `String` to `usize`. - let index_usize = match index.to_string().parse::() { - Ok(index_usize) => index_usize, - Err(_) => return Err(FrameError::invalid_index(index.to_string(), span)), - }; - - let element_type = elements.swap_remove(index_usize); - - Ok(element_type) - } - - /// - /// Returns the type of the array expression. - /// - fn parse_array(&mut self, expressions: &[SpreadOrExpression], span: &Span) -> Result { - // Store array element type. - let mut element_type = None; - - // Parse all array elements. - for expression in expressions { - // Get the type and count of elements in each spread or expression. - let type_ = self.parse_spread_or_expression(expression, span)?; - - // Assert that array element types are the same. - if let Some(prev_type) = element_type { - self.assert_equal(prev_type, type_.clone(), span); - } - - // Update array element type. - element_type = Some(type_); - } - - // Return an error for empty arrays. - let type_ = match element_type { - Some(type_) => type_, - None => return Err(FrameError::empty_array(span)), - }; - - Ok(Type::Array(Box::new(type_))) - } - - /// - /// Returns the type of the array initializer expression. - /// - fn parse_array_initializer( - &mut self, - array: &Expression, - dimensions: &ArrayDimensions, - span: &Span, - ) -> Result { - // Get element type. - let element_type = self.parse_expression(array)?; - - // Return an error for array initializers of length 0. - if dimensions.is_zero() { - return Err(FrameError::empty_array(span)); - } - - // Return array type. - Ok(Type::Array(Box::new(element_type))) - } - - /// - /// Returns the type and count of elements in a spread or expression. - /// - fn parse_spread_or_expression(&mut self, s_or_e: &SpreadOrExpression, span: &Span) -> Result { - match s_or_e { - SpreadOrExpression::Spread(expression) => { - // Parse the type of the spread array expression. - let array_type = self.parse_expression(expression)?; - - // Check that the type is an array. - match array_type { - Type::Array(element_type) => Ok(*element_type), - type_ => Err(FrameError::invalid_spread(type_, span)), - } - } - SpreadOrExpression::Expression(expression) => self.parse_expression(expression), - } - } - - /// - /// Returns `Type::U32` if the given index has `Type::TypeVariable`. - /// Hard codes all implicitly typed indices to u32. - /// Ex: `arr[0]` => `arr[0u32]` - /// - fn parse_index(&mut self, index: &Expression) -> Result { - Ok(match self.parse_expression(index)? { - Type::TypeVariable(_) => Type::IntegerType(IntegerType::U32), - type_ => type_, - }) - } - - /// - /// Returns the type of the accessed array element. - /// - fn parse_array_access(&mut self, array_type: Type, index: &Expression, span: &Span) -> Result { - // Check the type is an array. - let element_type = match array_type { - Type::Array(type_) => *type_, - type_ => return Err(FrameError::array_access(&type_, span)), - }; - - // Parse the expression type. - let type_ = self.parse_index(index)?; - - // Assert the type is an index. - self.assert_index(&type_, span); - - // Return the element type. - Ok(element_type) - } - - /// - /// Returns the type of the range of accessed array elements. - /// - fn parse_array_range_access( - &mut self, - array_type: Type, - left: Option<&Expression>, - right: Option<&Expression>, - span: &Span, - ) -> Result { - // Check the type is an array. - let element_type = match array_type { - Type::Array(type_) => *type_, - type_ => return Err(FrameError::array_access(&type_, span)), - }; - - if let Some(expression) = left { - // Parse the expression type. - let type_ = self.parse_index(expression)?; - - self.assert_index(&type_, span); - } - - if let Some(expression) = right { - // Parse the expression type. - let type_ = self.parse_index(expression)?; - - self.assert_index(&type_, span); - } - - // Return a new array type. - Ok(Type::Array(Box::new(element_type))) - } - - /// - /// Returns the Self type of the frame or an error if it does not exist. - /// - fn self_type_or_error(&self, span: &Span) -> Result { - self.self_type.clone().ok_or_else(|| FrameError::circuit_self(span)) - } - - /// - /// Returns the type of inline circuit expression. - /// - fn parse_circuit( - &mut self, - identifier: &Identifier, - members: &[CircuitVariableDefinition], - span: &Span, - ) -> Result { - // Check if identifier is Self circuit type. - let circuit_type = if identifier.is_self() { - // Get the Self type of the frame. - self.self_type_or_error(span)? - } else { - // Get circuit type. - self.user_defined_types - .get_circuit_type(&identifier.name) - .cloned() - .ok_or_else(|| FrameError::undefined_circuit(identifier))? - }; - - // Check the length of the circuit members. - if circuit_type.variables.len() != members.len() { - return Err(FrameError::num_circuit_variables( - circuit_type.variables.len(), - members.len(), - span, - )); - } - - // Assert members are circuit type member types. - for (expected_variable, actual_variable) in circuit_type.variables.iter().zip(members) { - // Parse actual variable expression. - let actual_type = self.parse_expression(&actual_variable.expression)?; - - // Assert expected variable type == actual variable type. - self.assert_equal(expected_variable.type_.clone(), actual_type, span) - } - - Ok(Type::Circuit(circuit_type.identifier)) - } - - /// - /// Returns the type of the accessed circuit member. - /// - fn parse_circuit_member_access( - &mut self, - type_: Type, - identifier: &Identifier, - span: &Span, - ) -> Result { - // Check that type is a circuit type. - let circuit_type = self.parse_circuit_name(type_, span)?; - - // Look for member with matching name. - Ok(circuit_type.member_type(&identifier)?) - } - - /// - /// Returns the type of the accessed circuit member when called as an expression. - /// - fn parse_expression_circuit_member_access( - &mut self, - expression: &Expression, - identifier: &Identifier, - span: &Span, - ) -> Result { - // Parse circuit name. - let type_ = self.parse_expression(expression)?; - - // Parse the circuit member access. - self.parse_circuit_member_access(type_, identifier, span) - } - - /// - /// Returns the type returned by calling the static circuit function. - /// - fn parse_static_circuit_function_access( - &mut self, - expression: &Expression, - identifier: &Identifier, - span: &Span, - ) -> Result { - // Parse the circuit name. - let type_ = self.parse_expression(expression)?; - - self.parse_circuit_member_access(type_, identifier, span) - } - - /// - /// Returns a `CircuitType` given a circuit expression. - /// - fn parse_circuit_name(&mut self, type_: Type, span: &Span) -> Result<&CircuitType, FrameError> { - // Check that type is a circuit type. - match type_ { - Type::Circuit(identifier) => { - // Lookup circuit identifier. - self.user_defined_types - .get_circuit_type(&identifier.name) - .ok_or_else(|| FrameError::undefined_circuit(&identifier)) - } - type_ => Err(FrameError::invalid_circuit(type_, span)), - } - } - - /// - /// Returns a `FunctionType` given a function expression. - /// - fn parse_function_name(&mut self, expression: &Expression, span: &Span) -> Result { - // Case 1: Call a function defined in the program file. - // Case 2: Call a circuit function. - // Case 3: Call a static circuit function. - // Return an Error in any other case. - match expression { - Expression::Identifier(identifier) => self.parse_program_function(identifier, span), - Expression::CircuitMemberAccess(CircuitMemberAccessExpression { circuit, name, span }) => { - self.parse_circuit_function(circuit, name, span, false) - } - Expression::CircuitStaticFunctionAccess(CircuitStaticFunctionAccessExpression { circuit, name, span }) => { - self.parse_circuit_function(circuit, name, span, true) - } - expression => Err(FrameError::invalid_function(expression, span)), - } - } - - /// - /// Returns a `FunctionType` given a function identifier. - /// - fn parse_program_function(&mut self, identifier: &Identifier, _span: &Span) -> Result { - self.user_defined_types - .get_function_type(&identifier.name) - .cloned() - .ok_or_else(|| FrameError::undefined_function(identifier)) - } - - /// - /// Returns a `CircuitFunctionType` given a circuit expression and function identifier. - /// - fn parse_circuit_function_type( - &mut self, - expression: &Expression, - identifier: &Identifier, - span: &Span, - ) -> Result<&FunctionType, FrameError> { - // Parse circuit name. - let type_ = self.parse_expression(expression)?; - - // Get circuit type. - let circuit_type = self.parse_circuit_name(type_, span)?; - - // Find circuit function by identifier. - circuit_type - .member_function_type(identifier) - .ok_or_else(|| FrameError::undefined_circuit_function(identifier)) - } - - /// - /// Returns a `FunctionType` given a circuit expression and non-static function identifier. - /// - fn parse_circuit_function( - &mut self, - expression: &Expression, - identifier: &Identifier, - span: &Span, - is_static: bool, - ) -> Result { - // Find circuit function type. - let function_type = self.parse_circuit_function_type(expression, identifier, span)?; - - // Case 1: static call + self keyword => Error - // Case 2: no static call + no self keywords => Error - // Case 3: static call + no self keywords => Ok - // Case 4: no static call + self keyword => Ok - if is_static && function_type.contains_self() { - return Err(FrameError::self_not_available(&identifier.span)); - } else if !is_static && !function_type.contains_self() { - return Err(FrameError::static_call_invalid(&identifier)); - } - - // Return the function type. - Ok(function_type.to_owned()) - } - - /// - /// Returns the type returned by calling the function. - /// - /// Does not attempt to evaluate the function call. We are just checking types at this step. - /// - fn parse_function_call( - &mut self, - expression: &Expression, - inputs: &[Expression], - span: &Span, - ) -> Result { - if let Expression::Identifier(id) = expression { - if id.is_core() { - return self.parse_core_function_call(&id.name, inputs, span); - } - } - - // Parse the function name. - let function_type = self.parse_function_name(expression, span)?; - - // Check the length of arguments - let num_inputs = function_type.num_inputs(); - - if num_inputs != inputs.len() { - return Err(FrameError::num_inputs(num_inputs, inputs.len(), span)); - } - - // Filter out `self` and `mut self` keywords. - // Assert function inputs are correct types. - for (expected_input, actual_input) in function_type.filter_self_inputs().zip(inputs) { - // Parse expected input type. - let expected_type = expected_input.type_(); - - // Parse actual input type. - let actual_type = self.parse_expression(actual_input)?; - - // Assert expected input type == actual input type. - self.assert_equal(expected_type, actual_type, span); - } - - // Return the function output type. - Ok(function_type.output.type_) - } - - /// - /// Returns the type returned by calling the core function. - /// - fn parse_core_function_call( - &mut self, - _name: &str, - _arguments: &[Expression], - _span: &Span, - ) -> Result { - unimplemented!("type checks for core function calls not implemented") - } - - /// - /// Returns `Ok` if all `TypeAssertions` can be solved successfully. - /// - pub(crate) fn check(self) -> Result<(), FrameError> { - let mut unsolved = self.type_assertions; - - // Solve all type equality assertions first. - let mut unsolved_membership = Vec::new(); - - while !unsolved.is_empty() { - // Pop type assertion from list - let type_assertion = unsolved.pop().unwrap(); - - // If it is a membership assertion, then skip it for now. - if let TypeAssertion::Membership(membership) = type_assertion { - unsolved_membership.push(membership); - - continue; - } - - // Collect `TypeVariablePairs` from the `TypeAssertion`. - let pairs = type_assertion.pairs()?; - - // If no pairs are found, attempt to evaluate the `TypeAssertion`. - if pairs.is_empty() { - // Evaluate the `TypeAssertion`. - type_assertion.evaluate()? - } else { - // Iterate over each `TypeVariable` -> `Type` pair. - for pair in pairs.get_pairs() { - // Substitute the `TypeVariable` for it's paired `Type` in all `TypeAssertion`s. - for original in &mut unsolved { - original.substitute(pair.first(), pair.second()) - } - - for original in &mut unsolved_membership { - original.substitute(pair.first(), pair.second()) - } - } - } - } - - // Solve all type membership assertions. - while !unsolved_membership.is_empty() { - // Pop type assertion from list - let type_assertion = unsolved_membership.pop().unwrap(); - - // Solve the membership assertion. - type_assertion.evaluate()?; - } - - Ok(()) - } -} diff --git a/type-inference/src/objects/mod.rs b/type-inference/src/objects/mod.rs deleted file mode 100644 index 632671824e..0000000000 --- a/type-inference/src/objects/mod.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (C) 2019-2021 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 . - -pub mod frame; -pub use self::frame::*; - -pub mod scope; -pub use self::scope::*; - -pub mod variable_table; -pub use self::variable_table::*; diff --git a/type-inference/src/objects/scope.rs b/type-inference/src/objects/scope.rs deleted file mode 100644 index c0749720b0..0000000000 --- a/type-inference/src/objects/scope.rs +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (C) 2019-2021 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::{ScopeError, VariableTable}; -use leo_symbol_table::{FunctionInputType, Type}; - -/// A structure for tracking the types of defined variables in a block of code. -#[derive(Clone, Default)] -pub struct Scope { - pub loop_variables: VariableTable, - pub variables: VariableTable, -} - -impl Scope { - /// - /// Returns a new `Scope` from an optional given `Scope`. - /// - /// The new scope will contain the variables of the optional given `Scope`. - /// - pub fn new(parent: Option) -> Self { - match parent { - Some(scope) => scope, - None => Self::default(), - } - } - - /// - /// Inserts a variable name -> type mapping into the loop variable table. - /// - pub fn insert_loop_variable(&mut self, name: String, type_: Type) -> Option { - self.loop_variables.insert(name, type_) - } - - /// - /// Inserts a variable name -> type mapping into the variable table. - /// - pub fn insert_variable(&mut self, name: String, type_: Type) -> Option { - self.variables.insert(name, type_) - } - - /// - /// Returns a reference to the type corresponding to the loop variable name. - /// - pub fn get_loop_variable(&self, name: &str) -> Option<&Type> { - self.loop_variables.get(name) - } - - /// - /// Returns a reference to the type corresponding to the variable name. - /// - /// Checks loop variables first, then non-loop variables. - /// - pub fn get_variable(&self, name: &str) -> Option<&Type> { - match self.get_loop_variable(name) { - Some(loop_variable_type) => Some(loop_variable_type), - None => self.variables.get(name), - } - } - - /// - /// Inserts a vector of function input types into the `Scope` variable table. - /// - pub fn insert_function_inputs(&mut self, function_inputs: &[FunctionInputType]) -> Result<(), ScopeError> { - self.variables - .insert_function_inputs(function_inputs) - .map_err(ScopeError::VariableTableError) - } -} diff --git a/type-inference/src/objects/variable_table.rs b/type-inference/src/objects/variable_table.rs deleted file mode 100644 index 52b98264ff..0000000000 --- a/type-inference/src/objects/variable_table.rs +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (C) 2019-2021 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::VariableTableError; -use leo_symbol_table::{FunctionInputType, Type}; - -use indexmap::IndexMap; - -/// Mapping of variable names to types -#[derive(Clone)] -pub struct VariableTable(pub IndexMap); - -impl VariableTable { - /// - /// Insert a name -> type pair into the variable table. - /// - /// If the variable table did not have this key present, [`None`] is returned. - /// - /// If the variable table did have this key present, the type is updated, and the old - /// type is returned. - /// - pub fn insert(&mut self, name: String, type_: Type) -> Option { - self.0.insert(name, type_) - } - - /// - /// Returns a reference to the type corresponding to the name. - /// - /// If the variable table did not have this key present, throw an undefined variable error - /// using the given span. - /// - pub fn get(&self, name: &str) -> Option<&Type> { - self.0.get(name) - } - - /// - /// Inserts a vector of function input types into the variable table. - /// - pub fn insert_function_inputs(&mut self, function_inputs: &[FunctionInputType]) -> Result<(), VariableTableError> { - for input in function_inputs { - let input_name = &input.identifier().name; - let input_type = input.type_(); - let input_span = input.span(); - - // Check for duplicate function input names. - let duplicate = self.insert(input_name.clone(), input_type); - - if duplicate.is_some() { - return Err(VariableTableError::duplicate_function_input(input_name, input_span)); - } - } - Ok(()) - } -} - -impl Default for VariableTable { - fn default() -> Self { - Self(IndexMap::new()) - } -} diff --git a/type-inference/src/type_inference.rs b/type-inference/src/type_inference.rs deleted file mode 100644 index 272c8cc96b..0000000000 --- a/type-inference/src/type_inference.rs +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright (C) 2019-2021 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::{Frame, Scope, TypeInferenceError}; -use leo_ast::{Circuit, CircuitMember, Function, Program}; -use leo_symbol_table::SymbolTable; - -/// A type inference check for a Leo program. -/// -/// A [`TypeInference`] type stores a stack of frames. A new frame is created for every -/// function. Frames store type assertions that assert an expression is a type. -/// Calling the `check()` method on a [`TypeInference`] checks that all type assertions are satisfied. -pub struct TypeInference { - table: SymbolTable, - frames: Vec, -} - -impl TypeInference { - /// - /// Creates and runs a new `TypeInference` check on a given program and symbol table. - /// - /// Evaluates all `TypeAssertion` predicates. - /// - #[allow(clippy::new_ret_no_self)] - pub fn new(program: &Program, symbol_table: SymbolTable) -> Result<(), TypeInferenceError> { - let mut type_inference = Self { - table: symbol_table, - frames: Vec::new(), - }; - - type_inference.parse_program(program)?; - - type_inference.check() - } - - /// - /// Collects a vector of `TypeAssertion` predicates from a program. - /// - fn parse_program(&mut self, program: &Program) -> Result<(), TypeInferenceError> { - // Parse circuit types in program context. - self.parse_circuits(program.circuits.iter().map(|(_identifier, circuit)| circuit))?; - - // Parse functions in program context. - self.parse_functions(program.functions.iter().map(|(_identifier, function)| function)) - } - - /// - /// Collects a vector of `Frames`s from a vector of circuit functions. - /// - fn parse_circuits<'a>(&mut self, circuits: impl Iterator) -> Result<(), TypeInferenceError> { - for circuit in circuits { - self.parse_circuit(circuit)?; - } - - Ok(()) - } - - /// - /// Collects a vector of `Frames`s from a circuit function. - /// - /// Each frame collects a vector of `TypeAssertion` predicates from each function. - /// - fn parse_circuit(&mut self, circuit: &Circuit) -> Result<(), TypeInferenceError> { - let name = &circuit.circuit_name.name; - - // Get circuit type from circuit symbol table. - let circuit_type = self.table.get_circuit_type(name).unwrap().clone(); - - // Create a new function for each circuit member function. - for circuit_member in &circuit.members { - // ignore circuit member variables - if let CircuitMember::CircuitFunction(function) = circuit_member { - // Collect `TypeAssertion` predicates from the function. - // Pass down circuit self type and circuit variable types to each function. - let frame = Frame::new_circuit_function( - function.to_owned(), - circuit_type.clone(), - Scope::default(), - self.table.clone(), - )?; - - self.frames.push(frame) - } - } - - Ok(()) - } - - /// - /// Collects a vector of `TypeAssertion` predicates from a vector of functions. - /// - fn parse_functions<'a>(&mut self, functions: impl Iterator) -> Result<(), TypeInferenceError> { - for function in functions { - self.parse_function(function)?; - } - - Ok(()) - } - - /// - /// Collects a vector of `TypeAssertion` predicates from a function. - /// - fn parse_function(&mut self, function: &Function) -> Result<(), TypeInferenceError> { - let frame = Frame::new_function(function.to_owned(), None, None, self.table.clone())?; - - self.frames.push(frame); - - Ok(()) - } - - /// - /// Returns the result of evaluating all `TypeAssertion` predicates. - /// - /// Will attempt to substitute a `Type` for all `TypeVariable`s. - /// Returns a `LeoResolvedAst` if all `TypeAssertion` predicates are true. - /// Returns ERROR if a `TypeAssertion` predicate is false or a solution does not exist. - /// - pub fn check(self) -> Result<(), TypeInferenceError> { - for frame in self.frames { - frame.check()?; - } - - Ok(()) - } -} diff --git a/type-inference/tests/arrays/empty_array.leo b/type-inference/tests/arrays/empty_array.leo deleted file mode 100644 index 7cf517014e..0000000000 --- a/type-inference/tests/arrays/empty_array.leo +++ /dev/null @@ -1,3 +0,0 @@ -function main() { - let a = [1u8; 0]; // Empty arrays are illegal in Leo programs since arrays cannot be resized. -} \ No newline at end of file diff --git a/type-inference/tests/arrays/index_implicit.leo b/type-inference/tests/arrays/index_implicit.leo deleted file mode 100644 index 351ca31eea..0000000000 --- a/type-inference/tests/arrays/index_implicit.leo +++ /dev/null @@ -1,5 +0,0 @@ -function main() { - let a = [0u32; 4]; - - let b = a[0]; // This should not cause a type inference error -} \ No newline at end of file diff --git a/type-inference/tests/arrays/invalid_array_access.leo b/type-inference/tests/arrays/invalid_array_access.leo deleted file mode 100644 index 0064d41ae6..0000000000 --- a/type-inference/tests/arrays/invalid_array_access.leo +++ /dev/null @@ -1,5 +0,0 @@ -function main() { - let a = (1u8, 2u8); - - let b = a[0]; // It is illegal to index into a tuple using bracket syntax. -} \ No newline at end of file diff --git a/type-inference/tests/arrays/invalid_spread.leo b/type-inference/tests/arrays/invalid_spread.leo deleted file mode 100644 index 0153b3d04b..0000000000 --- a/type-inference/tests/arrays/invalid_spread.leo +++ /dev/null @@ -1,5 +0,0 @@ -function main() { - let a: u8 = 1; - - let b = [...a]; -} \ No newline at end of file diff --git a/type-inference/tests/arrays/mod.rs b/type-inference/tests/arrays/mod.rs deleted file mode 100644 index b220ee818f..0000000000 --- a/type-inference/tests/arrays/mod.rs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (C) 2019-2021 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::TestTypeInference; - -#[test] -fn test_empty_array() { - let program_string = include_str!("empty_array.leo"); - - let check = TestTypeInference::new(program_string); - - check.expect_error(); -} - -#[test] -fn test_invalid_array_access() { - let program_string = include_str!("invalid_array_access.leo"); - - let check = TestTypeInference::new(program_string); - - check.expect_error(); -} - -#[test] -fn test_invalid_spread() { - let program_string = include_str!("invalid_spread.leo"); - - let check = TestTypeInference::new(program_string); - - check.expect_error(); -} - -#[test] -fn test_index_implicit() { - let program_string = include_str!("index_implicit.leo"); - - let check = TestTypeInference::new(program_string); - - check.check() -} - -#[test] -fn test_slice_implicit() { - let program_string = include_str!("slice_implicit.leo"); - - let check = TestTypeInference::new(program_string); - - check.check(); -} diff --git a/type-inference/tests/arrays/slice_implicit.leo b/type-inference/tests/arrays/slice_implicit.leo deleted file mode 100644 index 902f34465b..0000000000 --- a/type-inference/tests/arrays/slice_implicit.leo +++ /dev/null @@ -1,5 +0,0 @@ -function main() { - let a = [0u32; 4]; - - let b = a[0..2]; // This should not cause a type inference error -} \ No newline at end of file diff --git a/type-inference/tests/circuits/invalid_circuit.leo b/type-inference/tests/circuits/invalid_circuit.leo deleted file mode 100644 index aff73cc8d4..0000000000 --- a/type-inference/tests/circuits/invalid_circuit.leo +++ /dev/null @@ -1,4 +0,0 @@ -function main() { - let a = 1u8; - let b = a::foo(); // Variable `a` is not a circuit type. -} \ No newline at end of file diff --git a/type-inference/tests/circuits/mod.rs b/type-inference/tests/circuits/mod.rs deleted file mode 100644 index 2c7ae98918..0000000000 --- a/type-inference/tests/circuits/mod.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (C) 2019-2021 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::TestTypeInference; - -#[test] -fn test_invalid_circuit() { - let program_string = include_str!("invalid_circuit.leo"); - let check = TestTypeInference::new(program_string); - - check.expect_error(); -} diff --git a/type-inference/tests/empty.leo b/type-inference/tests/empty.leo deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/type-inference/tests/functions/invalid_function.leo b/type-inference/tests/functions/invalid_function.leo deleted file mode 100644 index 1e72c4e8d6..0000000000 --- a/type-inference/tests/functions/invalid_function.leo +++ /dev/null @@ -1,4 +0,0 @@ -function main() { - let a = 1u8; - let b = a(); // Variable `a` is not a function. -} \ No newline at end of file diff --git a/type-inference/tests/functions/mod.rs b/type-inference/tests/functions/mod.rs deleted file mode 100644 index 3bdbd70730..0000000000 --- a/type-inference/tests/functions/mod.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (C) 2019-2021 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::TestTypeInference; - -#[test] -fn test_invalid_function() { - let program_string = include_str!("invalid_function.leo"); - let check = TestTypeInference::new(program_string); - - check.expect_error(); -} diff --git a/type-inference/tests/mod.rs b/type-inference/tests/mod.rs deleted file mode 100644 index 9b42bfe3f6..0000000000 --- a/type-inference/tests/mod.rs +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (C) 2019-2021 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 . - -pub mod arrays; -pub mod circuits; -pub mod functions; -pub mod statements; -pub mod tuples; -pub mod variables; - -use leo_grammar::Grammar; -use leo_type_inference::TypeInference; - -use leo_ast::{Ast, Input, Program}; -use leo_imports::ImportParser; -use leo_symbol_table::SymbolTable; -use std::path::PathBuf; - -const TEST_PROGRAM_PATH: &str = ""; -const TEST_PROGRAM_NAME: &str = "test"; - -/// A helper struct to test a `TypeInference` check. -pub struct TestTypeInference { - program: Program, - symbol_table: SymbolTable, -} - -impl TestTypeInference { - pub fn new(program_string: &str) -> Self { - // Get test file path. - let file_path = PathBuf::from(TEST_PROGRAM_PATH); - - // Get parser syntax tree. - let ast = Grammar::new(&file_path, program_string).unwrap(); - - let result = Ast::new(TEST_PROGRAM_NAME, &ast); - // Get typed syntax tree. - // Always expect a valid SyntaxTree for testing. - let typed = result.unwrap(); - let program = typed.into_repr(); - - // Create empty import parser. - let import_parser = ImportParser::default(); - - // Create empty input. - let input = Input::new(); - - // Create symbol table. - let symbol_table = SymbolTable::new(&program, &import_parser, &input).unwrap(); - - // Store fields for new type inference check. - Self { program, symbol_table } - } - - pub fn check(self) { - TypeInference::new(&self.program, self.symbol_table).unwrap(); - } - - pub fn expect_error(self) { - assert!(TypeInference::new(&self.program, self.symbol_table).is_err()); - } -} - -#[test] -fn test_new() { - let program_string = include_str!("empty.leo"); - - let type_inference = TestTypeInference::new(program_string); - - type_inference.check() -} diff --git a/type-inference/tests/statements/array_loop_implicit.leo b/type-inference/tests/statements/array_loop_implicit.leo deleted file mode 100644 index 5b77fa6472..0000000000 --- a/type-inference/tests/statements/array_loop_implicit.leo +++ /dev/null @@ -1,7 +0,0 @@ -function main() { - let a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; - - for i in 0..10 { - console.log("{}", a[i]); - } -} \ No newline at end of file diff --git a/type-inference/tests/statements/loop_implicit.leo b/type-inference/tests/statements/loop_implicit.leo deleted file mode 100644 index b1358fe6d7..0000000000 --- a/type-inference/tests/statements/loop_implicit.leo +++ /dev/null @@ -1,5 +0,0 @@ -function main() { - for i in 0..10 { - console.log("{}", i); - } -} \ No newline at end of file diff --git a/type-inference/tests/statements/mod.rs b/type-inference/tests/statements/mod.rs deleted file mode 100644 index 1bbeaf9af8..0000000000 --- a/type-inference/tests/statements/mod.rs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (C) 2019-2021 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::TestTypeInference; - -#[test] -fn test_loop_implicit() { - let program_string = include_str!("loop_implicit.leo"); - - let check = TestTypeInference::new(program_string); - - check.check(); -} - -#[test] -fn test_array_loop_implicit() { - let program_string = include_str!("array_loop_implicit.leo"); - - let check = TestTypeInference::new(program_string); - - check.check(); -} diff --git a/type-inference/tests/tuples/invalid_tuple_access.leo b/type-inference/tests/tuples/invalid_tuple_access.leo deleted file mode 100644 index 1fc14e3a6b..0000000000 --- a/type-inference/tests/tuples/invalid_tuple_access.leo +++ /dev/null @@ -1,5 +0,0 @@ -function main() { - let a = [1u8; 3]; - - let b = a.0; // It is illegal to index into an array using dot syntax. -} \ No newline at end of file diff --git a/type-inference/tests/tuples/mod.rs b/type-inference/tests/tuples/mod.rs deleted file mode 100644 index ce2e92c760..0000000000 --- a/type-inference/tests/tuples/mod.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (C) 2019-2021 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::TestTypeInference; - -#[test] -fn test_invalid_tuple_access() { - let program_string = include_str!("invalid_tuple_access.leo"); - let check = TestTypeInference::new(program_string); - - check.expect_error(); -} diff --git a/type-inference/tests/variables/duplicate_variable.leo b/type-inference/tests/variables/duplicate_variable.leo deleted file mode 100644 index a748ef4efe..0000000000 --- a/type-inference/tests/variables/duplicate_variable.leo +++ /dev/null @@ -1,4 +0,0 @@ -function main() { - let a = 1u8; - let a = 2u8; // Redefining variables with the same name is unsafe in Leo. -} \ No newline at end of file diff --git a/type-inference/tests/variables/duplicate_variable_multi.leo b/type-inference/tests/variables/duplicate_variable_multi.leo deleted file mode 100644 index d0fabdea07..0000000000 --- a/type-inference/tests/variables/duplicate_variable_multi.leo +++ /dev/null @@ -1,3 +0,0 @@ -function main() { - let (a, a) = (2u8, 2u8); // Defining multiple variables with the same name is unsafe in Leo. -} \ No newline at end of file diff --git a/type-inference/tests/variables/mod.rs b/type-inference/tests/variables/mod.rs deleted file mode 100644 index 195152eba9..0000000000 --- a/type-inference/tests/variables/mod.rs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (C) 2019-2021 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::TestTypeInference; - -#[test] -fn test_duplicate_variable() { - let program_string = include_str!("duplicate_variable.leo"); - let check = TestTypeInference::new(program_string); - - check.expect_error(); -} - -#[test] -fn test_duplicate_variable_multi() { - let program_string = include_str!("duplicate_variable_multi.leo"); - let check = TestTypeInference::new(program_string); - - check.expect_error(); -} - -#[test] -fn test_not_enough_values() { - let program_string = include_str!("not_enough_values.leo"); - let check = TestTypeInference::new(program_string); - - check.expect_error(); -} - -#[test] -fn test_too_many_values() { - let program_string = include_str!("too_many_values.leo"); - let check = TestTypeInference::new(program_string); - - check.expect_error(); -} diff --git a/type-inference/tests/variables/not_enough_values.leo b/type-inference/tests/variables/not_enough_values.leo deleted file mode 100644 index 58b1ad7244..0000000000 --- a/type-inference/tests/variables/not_enough_values.leo +++ /dev/null @@ -1,3 +0,0 @@ -function main() { - let (a, b): (u8, u8) = 1; // A tuple of values must be used when defining two variables. -} \ No newline at end of file diff --git a/type-inference/tests/variables/too_many_values.leo b/type-inference/tests/variables/too_many_values.leo deleted file mode 100644 index bd3f551231..0000000000 --- a/type-inference/tests/variables/too_many_values.leo +++ /dev/null @@ -1,3 +0,0 @@ -function main() { - let (a, b): (u8, u8) = (1, 2, 3); // Cannot assign 2 variables to 3 values. -} \ No newline at end of file