From 7c03cc651b478b7f8cfc8b89a4d20849d47d557e Mon Sep 17 00:00:00 2001 From: Protryon Date: Wed, 20 Jan 2021 05:18:40 -0800 Subject: [PATCH] wip --- Cargo.lock | 1 + asg/src/checks/return_path.rs | 3 + asg/src/const_value.rs | 12 + asg/src/input.rs | 1 + asg/src/lib.rs | 26 +-- asg/src/program/function.rs | 2 + asg/src/statement/definition.rs | 1 + asg/src/statement/iteration.rs | 1 + asg/src/variable.rs | 2 + compiler/Cargo.toml | 4 + compiler/src/console/assert.rs | 12 +- compiler/src/console/console.rs | 8 +- compiler/src/console/format.rs | 8 +- compiler/src/constraints/constraints.rs | 17 +- compiler/src/definition/definition.rs | 14 +- compiler/src/definition/definitions.rs | 57 ----- compiler/src/definition/mod.rs | 3 - compiler/src/errors/statement.rs | 5 +- compiler/src/expression/arithmetic/add.rs | 8 - compiler/src/expression/arithmetic/div.rs | 8 - compiler/src/expression/arithmetic/mul.rs | 8 - compiler/src/expression/arithmetic/pow.rs | 8 - compiler/src/expression/arithmetic/sub.rs | 8 - compiler/src/expression/array/access.rs | 23 +- compiler/src/expression/array/array.rs | 211 +++--------------- compiler/src/expression/array/index.rs | 8 +- compiler/src/expression/binary/binary.rs | 15 +- compiler/src/expression/binary/operand.rs | 10 +- compiler/src/expression/circuit/access.rs | 75 ++----- compiler/src/expression/circuit/circuit.rs | 79 +++---- compiler/src/expression/circuit/mod.rs | 3 - .../src/expression/circuit/static_access.rs | 80 ------- .../src/expression/conditional/conditional.rs | 16 +- compiler/src/expression/expression.rs | 137 +++++------- .../src/expression/function/core_circuit.rs | 24 +- compiler/src/expression/function/function.rs | 68 +++--- compiler/src/expression/logical/and.rs | 2 +- compiler/src/expression/logical/not.rs | 6 +- compiler/src/expression/logical/or.rs | 2 +- compiler/src/expression/mod.rs | 4 +- compiler/src/expression/relational/eq.rs | 12 +- compiler/src/expression/relational/ge.rs | 10 +- compiler/src/expression/relational/gt.rs | 10 +- compiler/src/expression/relational/le.rs | 10 +- compiler/src/expression/relational/lt.rs | 10 +- compiler/src/expression/tuple/access.rs | 21 +- compiler/src/expression/tuple/tuple.rs | 34 +-- .../{identifier => variable_ref}/mod.rs | 4 +- .../variable_ref.rs} | 32 +-- compiler/src/function/function.rs | 64 +++--- compiler/src/function/input/function_input.rs | 4 +- compiler/src/function/main_function.rs | 66 +++--- compiler/src/function/result/result.rs | 28 +-- compiler/src/import/store/import.rs | 3 - compiler/src/program/program.rs | 26 ++- compiler/src/statement/assign/assign.rs | 50 +---- compiler/src/statement/assign/assignee.rs | 83 ++----- compiler/src/statement/block/block.rs | 10 +- .../src/statement/conditional/conditional.rs | 32 +-- .../src/statement/definition/definition.rs | 42 ++-- compiler/src/statement/iteration/iteration.rs | 26 +-- compiler/src/statement/return_/return_.rs | 28 +-- compiler/src/statement/statement.rs | 25 +-- compiler/src/value/group/group_type.rs | 4 +- compiler/src/value/group/input.rs | 8 +- .../src/value/group/targets/edwards_bls12.rs | 54 ++--- compiler/src/value/integer/integer.rs | 120 ++-------- compiler/src/value/value.rs | 138 +----------- 68 files changed, 548 insertions(+), 1386 deletions(-) delete mode 100644 compiler/src/definition/definitions.rs delete mode 100644 compiler/src/expression/circuit/static_access.rs rename compiler/src/expression/{identifier => variable_ref}/mod.rs (93%) rename compiler/src/expression/{identifier/identifier.rs => variable_ref/variable_ref.rs} (51%) diff --git a/Cargo.lock b/Cargo.lock index 12c0ba3c34..8f98aac73d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1309,6 +1309,7 @@ dependencies = [ "snarkvm-utilities", "thiserror", "tracing", + "uuid", ] [[package]] diff --git a/asg/src/checks/return_path.rs b/asg/src/checks/return_path.rs index e3d9af8d84..23ef3be975 100644 --- a/asg/src/checks/return_path.rs +++ b/asg/src/checks/return_path.rs @@ -46,6 +46,9 @@ impl MonoidalReducerStatement for ReturnPathReducer { } fn reduce_conditional_statement(&mut self, input: &ConditionalStatement, condition: BoolAnd, if_true: BoolAnd, if_false: Option) -> BoolAnd { + if if_false.as_ref().map(|x| x.0).unwrap_or(false) != if_true.0 { + self.record_error(input.span(), "cannot have asymmetrical return in if statement".to_string()); + } if_true.append(if_false.unwrap_or_else(|| BoolAnd(false))) } diff --git a/asg/src/const_value.rs b/asg/src/const_value.rs index 4a468da752..53178ab8c8 100644 --- a/asg/src/const_value.rs +++ b/asg/src/const_value.rs @@ -1,6 +1,7 @@ use crate::{ Type, IntegerType, AsgConvertError, Span }; use std::convert::TryInto; use num_bigint::BigInt; +use std::fmt; #[derive(Clone, Debug, PartialEq)] pub enum ConstInt { @@ -24,6 +25,17 @@ pub enum GroupCoordinate { Inferred, } +impl fmt::Display for GroupCoordinate { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + GroupCoordinate::Number(number) => write!(f, "{}", number), + GroupCoordinate::SignHigh => write!(f, "+"), + GroupCoordinate::SignLow => write!(f, "-"), + GroupCoordinate::Inferred => write!(f, "_"), + } + } +} + impl From<&leo_ast::GroupCoordinate> for GroupCoordinate { fn from(other: &leo_ast::GroupCoordinate) -> GroupCoordinate { use leo_ast::GroupCoordinate::*; diff --git a/asg/src/input.rs b/asg/src/input.rs index 77fcc69831..6840fb29e6 100644 --- a/asg/src/input.rs +++ b/asg/src/input.rs @@ -66,6 +66,7 @@ impl Input { state_leaf, container_circuit: container_circuit.clone(), container: Arc::new(RefCell::new(crate::InnerVariable { + id: uuid::Uuid::new_v4(), name: Identifier::new("input".to_string()), type_: Type::Circuit(container_circuit), mutable: false, diff --git a/asg/src/lib.rs b/asg/src/lib.rs index 2fc0d15044..cbb364a0c6 100644 --- a/asg/src/lib.rs +++ b/asg/src/lib.rs @@ -1,46 +1,46 @@ #[macro_use] extern crate thiserror; -mod node; +pub mod node; pub use node::*; -mod type_; +pub mod type_; pub use type_::*; -mod program; +pub mod program; pub use program::*; -mod expression; +pub mod expression; pub use expression::*; -mod statement; +pub mod statement; pub use statement::*; -mod variable; +pub mod variable; pub use variable::*; -mod scope; +pub mod scope; pub use scope::*; -mod error; +pub mod error; pub use error::*; -mod import; +pub mod import; pub use import::*; -mod const_value; +pub mod const_value; pub use const_value::*; mod input; pub use input::*; -mod prelude; +pub mod prelude; pub use prelude::*; -mod reducer; +pub mod reducer; pub use reducer::*; -mod checks; +pub mod checks; pub use checks::*; pub use leo_ast::{ Span, Identifier }; diff --git a/asg/src/program/function.rs b/asg/src/program/function.rs index e770e7e559..34a1514cbc 100644 --- a/asg/src/program/function.rs +++ b/asg/src/program/function.rs @@ -101,6 +101,7 @@ impl FunctionBody { if function.qualifier != FunctionQualifier::Static { let circuit = function.circuit.borrow(); let self_variable = Arc::new(RefCell::new(crate::InnerVariable { + id: Uuid::new_v4(), name: Identifier::new("self".to_string()), type_: Type::Circuit(circuit.as_ref().unwrap().upgrade().clone().unwrap()), mutable: function.qualifier == FunctionQualifier::MutSelfRef, @@ -119,6 +120,7 @@ impl FunctionBody { FunctionInput::MutSelfKeyword(_) => {}, FunctionInput::Variable(leo_ast::FunctionInputVariable { identifier, mutable, type_, span: _span }) => { let variable = Arc::new(RefCell::new(crate::InnerVariable { + id: Uuid::new_v4(), name: identifier.clone(), type_: scope_borrow.resolve_ast_type(&type_)?, mutable: *mutable, diff --git a/asg/src/statement/definition.rs b/asg/src/statement/definition.rs index 40a67c1ee4..f6526f16ac 100644 --- a/asg/src/statement/definition.rs +++ b/asg/src/statement/definition.rs @@ -59,6 +59,7 @@ impl FromAst for DefinitionStatement { return Err(AsgConvertError::illegal_ast_structure("cannot have const mut")); } variables.push(Arc::new(RefCell::new(InnerVariable { + id: uuid::Uuid::new_v4(), name: variable.identifier.clone(), type_: type_ .ok_or_else(|| AsgConvertError::unresolved_type(&variable.identifier.name, &statement.span))?, diff --git a/asg/src/statement/iteration.rs b/asg/src/statement/iteration.rs index a4feb6c8a6..3920998833 100644 --- a/asg/src/statement/iteration.rs +++ b/asg/src/statement/iteration.rs @@ -25,6 +25,7 @@ impl FromAst for IterationStatement { let start = Arc::::from_ast(scope, &statement.start, expected_index_type.clone())?; let stop = Arc::::from_ast(scope, &statement.stop, expected_index_type)?; let variable = Arc::new(RefCell::new(InnerVariable { + id: uuid::Uuid::new_v4(), name: statement.variable.clone(), type_: start.get_type().ok_or_else(|| AsgConvertError::unresolved_type(&statement.variable.name, &statement.span))?, mutable: false, diff --git a/asg/src/variable.rs b/asg/src/variable.rs index a5bb766b1c..89b180f4cf 100644 --- a/asg/src/variable.rs +++ b/asg/src/variable.rs @@ -2,6 +2,7 @@ use leo_ast::Identifier; use crate::{ Type, Expression, ConstValue, Statement }; use std::sync::{ Arc, Weak }; use std::cell::RefCell; +use uuid::Uuid; //todo: fill out pub enum VariableDeclaration { @@ -13,6 +14,7 @@ pub enum VariableDeclaration { } pub struct InnerVariable { + pub id: Uuid, pub name: Identifier, pub type_: Type, pub mutable: bool, diff --git a/compiler/Cargo.toml b/compiler/Cargo.toml index 4cb4fde38a..a8a03a19ef 100644 --- a/compiler/Cargo.toml +++ b/compiler/Cargo.toml @@ -120,6 +120,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/console/assert.rs b/compiler/src/console/assert.rs index 3b946959b3..ee43b2659b 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, Type}; +use std::sync::Arc; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -37,14 +38,13 @@ impl> ConstrainedProgram { 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, file_scope, function_scope, expression)?; // If the indicator bit is false, do not evaluate the assertion // This is okay since we are not enforcing any constraints @@ -57,7 +57,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 +65,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 8035a9238f..cde0c2f21d 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}, @@ -31,11 +31,11 @@ impl> ConstrainedProgram { 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, file_scope, function_scope, indicator, expression, &console.span.clone().unwrap_or_default())?; } ConsoleFunction::Debug(string) => { let string = self.format(cs, file_scope, function_scope, string)?; diff --git a/compiler/src/console/format.rs b/compiler/src/console/format.rs index 1c16f46955..3bde7cb706 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}, @@ -30,7 +30,7 @@ impl> ConstrainedProgram { 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() { @@ -51,8 +51,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, file_scope, function_scope, parameter)?; result = result.replacen("{}", ¶meter_value.to_string(), 1); } diff --git a/compiler/src/constraints/constraints.rs b/compiler/src/constraints/constraints.rs index 68886f4981..ad6437c773 100644 --- a/compiler/src/constraints/constraints.rs +++ b/compiler/src/constraints/constraints.rs @@ -18,9 +18,7 @@ use crate::{ errors::CompilerError, - new_scope, ConstrainedProgram, - ConstrainedValue, GroupType, OutputBytes, OutputFile, @@ -43,15 +41,15 @@ pub fn generate_constraints, CS: Constrai ) -> Result { let mut resolved_program = ConstrainedProgram::::new(); let program_name = program.borrow().name.clone(); - let main_function_name = new_scope(&program_name, "main"); - resolved_program.store_definitions(program)?; - - let main = resolved_program.get(&main_function_name).ok_or(CompilerError::NoMain)?; + let main = { + let program = program.borrow(); + program.functions.get("main").cloned() + }; match main.clone() { - ConstrainedValue::Function(_circuit_identifier, function) => { - let result = resolved_program.enforce_main_function(cs, &program_name, function, input)?; + Some(function) => { + let result = resolved_program.enforce_main_function(cs, &program_name, &function, input)?; Ok(result) } _ => Err(CompilerError::NoMainFunction), @@ -67,9 +65,6 @@ pub fn generate_test_constraints>( let mut resolved_program = ConstrainedProgram::::new(); let program_name = program.borrow().name.clone(); - // Store definitions - resolved_program.store_definitions(&program)?; - // Get default input let default = input.pairs.get(&program_name); diff --git a/compiler/src/definition/definition.rs b/compiler/src/definition/definition.rs index ca9623ec0c..71a98cca08 100644 --- a/compiler/src/definition/definition.rs +++ b/compiler/src/definition/definition.rs @@ -17,11 +17,11 @@ //! Stores all defined names in a compiled Leo program. use crate::{ - program::{new_scope, ConstrainedProgram}, + program::{ConstrainedProgram}, value::ConstrainedValue, GroupType, }; -use leo_ast::Identifier; +use leo_asg::Variable; use snarkvm_models::curves::{Field, PrimeField}; @@ -29,17 +29,15 @@ impl> ConstrainedProgram { pub fn store_definition( &mut self, function_scope: &str, - mutable: bool, - identifier: Identifier, + 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.clone(), value); } } diff --git a/compiler/src/definition/definitions.rs b/compiler/src/definition/definitions.rs deleted file mode 100644 index 106234f6cf..0000000000 --- a/compiler/src/definition/definitions.rs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (C) 2019-2020 Aleo Systems Inc. -// This file is part of the Leo library. - -// The Leo library is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// The Leo library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with the Leo library. If not, see . - -//! Stores all defined names in a compiled Leo program. - -use crate::{ - errors::ImportError, - program::{new_scope, ConstrainedProgram}, - value::ConstrainedValue, - GroupType, -}; -use leo_asg::Program; - -use snarkvm_models::curves::{Field, PrimeField}; - -impl> ConstrainedProgram { - pub fn store_definitions( - &mut self, - program: &Program, - ) -> Result<(), ImportError> { - let program = program.borrow(); - let program_name = program.name.trim_end_matches(".leo"); - - // evaluate and store all circuit definitions - program.circuits.iter().for_each(|(identifier, circuit)| { - let resolved_circuit_name = new_scope(program_name, &identifier); - 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); - self.store( - resolved_function_name, - ConstrainedValue::Function(None, function.clone()), - ); - }); - - Ok(()) - } -} diff --git a/compiler/src/definition/mod.rs b/compiler/src/definition/mod.rs index c62d778a71..2b20761620 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/statement.rs b/compiler/src/errors/statement.rs index eedff6892f..a6e5238a10 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_ast::{Error as FormattedError, Span}; +use leo_asg::Type; 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 a64218c78f..5890a00253 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 77a86c10b5..eacb9dcf53 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 913c31f19a..2c6e417b92 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 a48458482f..4996b0144d 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 632ed925fb..1b02c6bf9c 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 1079a46df1..834cc591f3 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}, @@ -31,12 +32,11 @@ impl> ConstrainedProgram { 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, file_scope, function_scope, array)? { ConstrainedValue::Array(array) => array, value => return Err(ExpressionError::undefined_array(value.to_string(), span.to_owned())), }; @@ -51,22 +51,21 @@ impl> ConstrainedProgram { 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, file_scope, function_scope, array)? { ConstrainedValue::Array(array) => array, value => return Err(ExpressionError::undefined_array(value.to_string(), span.to_owned())), }; - let from_resolved = match left { + let from_resolved = match left.as_deref() { Some(from_index) => self.enforce_index(cs, file_scope, function_scope, from_index, span)?, None => 0usize, // Array slice starts at index 0 }; - let to_resolved = match right { + let to_resolved = match right.as_deref() { Some(to_index) => self.enforce_index(cs, file_scope, function_scope, to_index, span)?, None => array.len(), // Array slice ends at array length }; diff --git a/compiler/src/expression/array/array.rs b/compiler/src/expression/array/array.rs index c52fec00d1..a89b394963 100644 --- a/compiler/src/expression/array/array.rs +++ b/compiler/src/expression/array/array.rs @@ -18,11 +18,12 @@ use crate::{ errors::ExpressionError, - program::{new_scope, ConstrainedProgram}, + program::{ConstrainedProgram}, value::ConstrainedValue, GroupType, }; -use leo_ast::{ArrayDimensions, Expression, PositiveNumber, Span, SpreadOrExpression, Type}; +use leo_asg::{Expression, Span}; +use std::sync::Arc; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -36,63 +37,26 @@ impl> ConstrainedProgram { cs: &mut CS, file_scope: &str, function_scope: &str, - mut expected_type: Option, - array: Vec, + array: &Vec<(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 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.into_iter() { + let element_value = self.enforce_expression( + cs, + file_scope, + function_scope, + element, + )?; + if *is_spread { + match element_value { + ConstrainedValue::Array(array) => result.extend(array), + _ => unimplemented!(), // type should already be checked } + } else { + result.push(element_value); } } @@ -116,142 +80,19 @@ impl> ConstrainedProgram { cs: &mut CS, file_scope: &str, function_scope: &str, - expected_type: Option, - element_expression: Expression, - mut actual_dimensions: ArrayDimensions, + element_expression: &Arc, + actual_size: usize, span: Span, ) -> 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 - - 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. - 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) - } 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(); + let mut value = + self.enforce_expression(cs, file_scope, function_scope, element_expression)?; - // 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)); + // Allocate the array. + let array = vec![value; actual_size]; - // 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)) -} + // Set the array value. + value = ConstrainedValue::Array(array); -/// -/// 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 0c67ed4cdc..8d6bd8445f 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}, @@ -30,11 +31,10 @@ impl> ConstrainedProgram { 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, file_scope, function_scope, 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 270e05fb1d..5c0662ab59 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, Span}; +use std::sync::Arc; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -33,17 +34,15 @@ impl> ConstrainedProgram { cs: &mut CS, file_scope: &str, function_scope: &str, - expected_type: Option, - left: Expression, - right: Expression, + left: &Arc, + right: &Arc, span: &Span, ) -> Result, ExpressionError> { + //todo: what are these expected typeS??? let mut resolved_left = - self.enforce_operand(cs, file_scope, function_scope, expected_type.clone(), left, span)?; + self.enforce_operand(cs, file_scope, function_scope, left)?; 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)?; + self.enforce_operand(cs, file_scope, function_scope, right)?; Ok((resolved_left, resolved_right)) } diff --git a/compiler/src/expression/binary/operand.rs b/compiler/src/expression/binary/operand.rs index 44730d2fea..8fb3a20f2c 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}, @@ -33,14 +34,11 @@ impl> ConstrainedProgram { 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, file_scope, function_scope, 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 244fc4512c..12d1e3ea8a 100644 --- a/compiler/src/expression/circuit/access.rs +++ b/compiler/src/expression/circuit/access.rs @@ -18,11 +18,11 @@ use crate::{ errors::ExpressionError, - program::{new_scope, ConstrainedProgram}, + program::{ConstrainedProgram}, value::ConstrainedValue, GroupType, }; -use leo_ast::{Expression, Identifier, Span, Type}; +use leo_asg::{CircuitAccessExpression, Span, Node}; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -38,60 +38,29 @@ impl> ConstrainedProgram { cs: &mut CS, file_scope: &str, function_scope: &str, - expected_type: Option, - circuit_identifier: Expression, - circuit_member: Identifier, - span: Span, + expr: &CircuitAccessExpression, + span: &Span, ) -> 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()); - } - } - } - ConstrainedValue::Static(value) => { - return Err(ExpressionError::invalid_static_access(value.to_string(), span)); + 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, file_scope, function_scope, 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(), + )) } - _ => {} - } - 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 09f9c525d6..dffb47b3e8 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}, @@ -35,63 +35,42 @@ impl> ConstrainedProgram { 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); - if identifier.is_self() { - program_identifier = file_scope.to_string(); - } - - 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()); + let circuit = expr.circuit.body.borrow().upgrade().expect("circuit init stale circuit ref"); + let members = circuit.members.borrow(); + let circuit_identifier = expr.circuit.name.borrow().clone(); - 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)); + let mut resolved_members = Vec::with_capacity(members.len()); - resolved_members.push(ConstrainedCircuitMember(identifier, constrained_function_value)); + // 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, + file_scope, + function_scope, + inner, + )?; + resolved_members.push(ConstrainedCircuitMember(name.clone(), variable_value)); } - }; + _ => return Err(ExpressionError::expected_circuit_member(name.to_string(), span.clone())) + } } - Ok(ConstrainedValue::CircuitExpression( - circuit_identifier, + let id = uuid::Uuid::new_v4(); + let value = ConstrainedValue::CircuitExpression( + circuit, + id.clone(), resolved_members, - )) + ); + self.store(id, value.clone()); + Ok(value) } } diff --git a/compiler/src/expression/circuit/mod.rs b/compiler/src/expression/circuit/mod.rs index 0f44eabce1..ad606adc8e 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 b10e9d0440..0000000000 --- a/compiler/src/expression/circuit/static_access.rs +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (C) 2019-2020 Aleo Systems Inc. -// This file is part of the Leo library. - -// The Leo library is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// The Leo library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with the Leo library. If not, see . - -//! 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 8d55c79741..039680c1ac 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}, @@ -32,21 +33,20 @@ impl> ConstrainedProgram { 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)? { + match self.enforce_expression(cs, file_scope, function_scope, 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, file_scope, function_scope, first)?; - let second_value = self.enforce_operand(cs, file_scope, function_scope, expected_type, second, span)?; + let second_value = self.enforce_operand(cs, file_scope, function_scope, second)?; let unique_namespace = cs.ns(|| { format!( diff --git a/compiler/src/expression/expression.rs b/compiler/src/expression/expression.rs index 23a7f66da5..9b4ff9a1bf 100644 --- a/compiler/src/expression/expression.rs +++ b/compiler/src/expression/expression.rs @@ -22,17 +22,17 @@ use crate::{ logical::*, program::ConstrainedProgram, relational::*, - value::{boolean::input::new_bool_constant, implicit::*, ConstrainedValue}, - Address, FieldType, + value::{ConstrainedValue, Address, Integer}, GroupType, - Integer, }; -use leo_ast::{expression::*, Expression, Type}; +use leo_asg::{expression::*, Expression, ConstValue, Node}; +use std::sync::Arc; use snarkvm_models::{ curves::{Field, PrimeField}, gadgets::r1cs::ConstraintSystem, + gadgets::utilities::boolean::Boolean, }; impl> ConstrainedProgram { @@ -41,52 +41,39 @@ impl> ConstrainedProgram { 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(file_scope, function_scope, 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, &span)), + 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 }) => { + Expression::Binary(BinaryExpression { left, right, operation, .. }) => { 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, + left, + right, &span, )?; - 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 +86,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,15 +96,15 @@ 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)?; + self.enforce_expression(cs, file_scope, function_scope, 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, + self.enforce_operand(cs, file_scope, function_scope, inner)?, + &span, )?), }, @@ -125,96 +112,90 @@ impl> ConstrainedProgram { condition, if_true, if_false, - span, + .. }) => self.enforce_conditional_expression( cs, file_scope, function_scope, - expected_type, - *condition, - *if_true, - *if_false, + 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, file_scope, function_scope, elements, span) } Expression::ArrayInit(ArrayInitExpression { element, - dimensions, - span, + len, + .. }) => self.enforce_array_initializer( cs, file_scope, function_scope, - expected_type, - *element, - dimensions, + element, + *len, 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, file_scope, function_scope, array, index, &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), + array, + left.as_ref(), + right.as_ref(), &span, ), // Tuples - Expression::TupleInit(TupleInitExpression { elements, span }) => { - self.enforce_tuple(cs, file_scope, function_scope, expected_type, elements, span) + Expression::TupleInit(TupleInitExpression { elements, .. }) => { + self.enforce_tuple(cs, file_scope, function_scope, elements, &span) } - Expression::TupleAccess(TupleAccessExpression { tuple, index, span }) => { - self.enforce_tuple_access(cs, file_scope, function_scope, expected_type, *tuple, index, &span) + Expression::TupleAccess(TupleAccessExpression { tuple_ref, index, .. }) => { + self.enforce_tuple_access(cs, file_scope, function_scope, tuple_ref, *index, &span) } // Circuits - Expression::CircuitInit(CircuitInitExpression { name, members, span }) => { - self.enforce_circuit(cs, file_scope, function_scope, name, members, span) + Expression::CircuitInit(expr) => { + self.enforce_circuit(cs, file_scope, function_scope, expr, &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::CircuitAccess(expr) => { + self.enforce_circuit_access(cs, file_scope, function_scope, expr, &span) } // Functions Expression::Call(CallExpression { function, + target, arguments, - span, + .. }) => match *function { - Expression::Identifier(id) if id.is_core() => self.enforce_core_circuit_call_expression( + function if function.name.borrow().is_core() => self.enforce_core_circuit_call_expression( cs, file_scope, function_scope, - expected_type, - id.name, + function.name.borrow().name.clone(), arguments, - span, + &span, ), function => self.enforce_function_call_expression( cs, file_scope, function_scope, - expected_type, - function, + &function, + target.as_ref(), arguments, - span, + &span, ), }, } diff --git a/compiler/src/expression/function/core_circuit.rs b/compiler/src/expression/function/core_circuit.rs index 5e74cf38cf..5dcc97cc17 100644 --- a/compiler/src/expression/function/core_circuit.rs +++ b/compiler/src/expression/function/core_circuit.rs @@ -15,13 +15,14 @@ // along with the Leo library. If not, see . use crate::{program::ConstrainedProgram, value::ConstrainedValue, GroupType}; -use crate::errors::{ExpressionError, FunctionError}; -use leo_ast::{Expression, Span, Type}; +use crate::errors::{ExpressionError}; +use leo_asg::{Expression, Span}; use leo_core::call_core_circuit; use snarkvm_models::{ curves::{Field, PrimeField}, gadgets::r1cs::ConstraintSystem, }; +use std::sync::Arc; impl> ConstrainedProgram { /// Call a default core circuit function with arguments @@ -31,15 +32,14 @@ impl> ConstrainedProgram { cs: &mut CS, file_scope: &str, function_scope: &str, - expected_type: Option, core_circuit: String, - arguments: Vec, - span: Span, + arguments: &Vec>, + 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 argument_value = self.enforce_expression(cs, file_scope, function_scope, argument)?; let core_function_argument = argument_value.to_value(); argument_values.push(core_function_argument); @@ -53,22 +53,12 @@ impl> ConstrainedProgram { let return_value = if returns.len() == 1 { // The function has a single return - returns[0].clone() + returns.into_iter().next().unwrap() } else { // The function has multiple returns ConstrainedValue::Tuple(returns) }; - // 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), - ))); - } - } - Ok(return_value) } } diff --git a/compiler/src/expression/function/function.rs b/compiler/src/expression/function/function.rs index 24f510c2fe..bbdc5ce9a5 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, Span, Function}; +use std::sync::Arc; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -31,49 +32,52 @@ impl> ConstrainedProgram { cs: &mut CS, file_scope: &str, function_scope: &str, - expected_type: Option, - function: Expression, - arguments: Vec, - span: Span, + function: &Arc, + target: Option<&Arc>, + arguments: &Vec>, + 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( + let target = if let Some(target) = target { + Some(self.enforce_expression(cs, file_scope, function_scope, target)?) + } else { + None + }; + + let old_self_alias = self.self_alias.take(); + self.self_alias = if let Some(target) = &target { + let self_var = function.scope.borrow().resolve_variable("self").expect("attempted to call static function from non-static context"); + match target { + ConstrainedValue::CircuitExpression(circuit, id, values) => { + assert!(Some(&circuit.circuit) == function.function.circuit.borrow().map(|x| x.upgrade()).flatten().as_ref()); + Some((self_var.borrow().id.clone(), id.clone())) + }, + _ => panic!("attempted to pass non-circuit as target"), + } + } else { + None + }; + + let return_value = self.enforce_function( &mut cs.ns(name_unique), - &outer_scope, + file_scope, function_scope, - function_call, + &function, + target, arguments, - &declared_circuit_reference, ) - .map_err(|error| ExpressionError::from(Box::new(error))) + .map_err(|error| ExpressionError::from(Box::new(error)))?; + + Ok(return_value) } } diff --git a/compiler/src/expression/logical/and.rs b/compiler/src/expression/logical/and.rs index 1000a2b7de..e27833de02 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 1401ed99d2..cbcc2693da 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 d8bce5d7cc..b8cb07e403 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 45fcde4b00..636dbe6e5e 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 fc140d9203..aa3f9be174 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 9ffdae4f7e..a4f74d2f85 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::{ @@ -36,14 +36,6 @@ pub fn evaluate_ge, CS: ConstraintSystem< (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 7f7e817660..d3442fd8a7 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::{ @@ -36,14 +36,6 @@ pub fn evaluate_gt, CS: ConstraintSystem< (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 ef615a76b4..fb539498e4 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::{ @@ -36,14 +36,6 @@ pub fn evaluate_le, CS: ConstraintSystem< (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 f77fdb2a73..bef54f4f3b 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::{ @@ -36,14 +36,6 @@ pub fn evaluate_lt, CS: ConstraintSystem< (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 1218cdf15b..c1022778c7 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}, @@ -31,25 +32,21 @@ impl> ConstrainedProgram { 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, file_scope, function_scope, 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 358def9bdf..73b79499ab 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, Span}; +use std::sync::Arc; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -31,36 +32,13 @@ impl> ConstrainedProgram { cs: &mut CS, file_scope: &str, function_scope: &str, - expected_type: Option, - tuple: Vec, - span: Span, + tuple: &Vec>, + span: &Span, ) -> 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()) - }; + for (i, expression) in tuple.iter().enumerate() { - result.push(self.enforce_expression(cs, file_scope, function_scope, type_, expression)?); + result.push(self.enforce_expression(cs, file_scope, function_scope, 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 e7782a19b7..fa934f6e28 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/expression/identifier/identifier.rs b/compiler/src/expression/variable_ref/variable_ref.rs similarity index 51% rename from compiler/src/expression/identifier/identifier.rs rename to compiler/src/expression/variable_ref/variable_ref.rs index de30d83912..412b155802 100644 --- a/compiler/src/expression/identifier/identifier.rs +++ b/compiler/src/expression/variable_ref/variable_ref.rs @@ -18,48 +18,30 @@ use crate::{ errors::ExpressionError, - program::{new_scope, ConstrainedProgram}, + program::{ConstrainedProgram}, value::ConstrainedValue, - Address, GroupType, }; -use leo_ast::{Identifier, Type}; +use leo_asg::{VariableRef}; use snarkvm_models::curves::{Field, PrimeField}; impl> ConstrainedProgram { /// Enforce a variable expression by getting the resolved value - pub fn evaluate_identifier( + pub fn evaluate_ref( &mut self, file_scope: &str, function_scope: &str, - expected_type: Option, - unresolved_identifier: Identifier, + variable_ref: &VariableRef, ) -> 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 + let variable = variable_ref.variable.borrow(); + let result_value = if let Some(value) = self.get(&variable.id) { value.clone() - } else if expected_type.is_some() && expected_type.unwrap() == 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)); + return Err(ExpressionError::undefined_identifier(variable.name.clone())); // todo: probably can be a panic here instead }; - result_value.resolve_type(expected_type, &unresolved_identifier.span)?; - Ok(result_value) } } diff --git a/compiler/src/function/function.rs b/compiler/src/function/function.rs index a0a20a1a19..7cc1061c9f 100644 --- a/compiler/src/function/function.rs +++ b/compiler/src/function/function.rs @@ -38,42 +38,40 @@ impl> ConstrainedProgram { scope: &str, caller_scope: &str, function: &Arc, - input: Option<&Expression>, - self_: Option<&Expression>, - arguments: Vec<&Expression>, - declared_circuit_reference: &str, + self_: Option>, + arguments: &Vec>, ) -> Result, FunctionError> { let function_name = new_scope(scope, &function.function.name.borrow().name.clone()); // Store if function contains input `mut self`. let mut_self = function.function.qualifier == FunctionQualifier::MutSelfRef; - if function.function.has_input { - if let Some(input) = input { - // todo: enforce self & input - let value = - self.enforce_function_input(cs, scope, caller_scope, &function_name, None, input)?; - - self.store(new_scope(&function_name, "input"), value); - } else { - return Err(FunctionError::input_not_found("input".to_string(), function.span.unwrap_or_default())); - } - } - - match function.function.qualifier { - FunctionQualifier::SelfRef | FunctionQualifier::MutSelfRef => { - if let Some(input) = input { - // todo: enforce self & input - let value = - self.enforce_function_input(cs, scope, caller_scope, &function_name, None, self_)?; - - self.store(new_scope(&function_name, "self"), value); - } else { - return Err(FunctionError::input_not_found("self".to_string(), function.span.unwrap_or_default())); - } - }, - FunctionQualifier::Static => (), - } + // if function.function.has_input { + // // let input_var = function.scope. + // if let Some(input) = input { + // let variable = function.scope.borrow().resolve_variable("input").expect("no input variable in scope when function is qualified"); + + // let value = + // self.enforce_function_input(cs, scope, caller_scope, &function_name, None, input)?; + + // self.store(variable.borrow().id.clone(), value); + // } else { + // return Err(FunctionError::input_not_found("input".to_string(), function.span.unwrap_or_default())); + // } + // } + + // match function.function.qualifier { + // FunctionQualifier::SelfRef | FunctionQualifier::MutSelfRef => { + // if let Some(value) = self_ { + // // todo: enforce self & input + // let variable = function.scope.borrow().resolve_variable("self").expect("no self variable in scope when function is qualified"); + // self.store(variable.borrow().id.clone(), value); + // } else { + // return Err(FunctionError::input_not_found("self".to_string(), function.span.unwrap_or_default())); + // } + // }, + // FunctionQualifier::Static => (), + // } if function.arguments.len() != arguments.len() { return Err(FunctionError::input_not_found("arguments length invalid".to_string(), function.span.unwrap_or_default())); } @@ -95,9 +93,7 @@ impl> ConstrainedProgram { input_value = ConstrainedValue::Mutable(Box::new(input_value)) } - // Store input as variable with {function_name}_{input_name} - let input_program_identifier = new_scope(&function_name, &variable.name.name); - self.store(input_program_identifier, input_value); + self.store(variable.id.clone(), input_value); } // Evaluate every statement in the function and save all potential results @@ -112,8 +108,6 @@ impl> ConstrainedProgram { &function_name, &indicator, &function.body, - &output, - declared_circuit_reference, mut_self, )?; diff --git a/compiler/src/function/input/function_input.rs b/compiler/src/function/input/function_input.rs index aee14ff3e6..8b23cc8347 100644 --- a/compiler/src/function/input/function_input.rs +++ b/compiler/src/function/input/function_input.rs @@ -18,7 +18,7 @@ use crate::{errors::FunctionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType}; -use leo_ast::{Expression, Type}; +use leo_asg::{Expression, Type}; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -33,7 +33,7 @@ impl> ConstrainedProgram { caller_scope: &str, function_name: &str, expected_type: Option, - input: Expression, + 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 diff --git a/compiler/src/function/main_function.rs b/compiler/src/function/main_function.rs index 4c0fdf2a95..ad3bf4cf32 100644 --- a/compiler/src/function/main_function.rs +++ b/compiler/src/function/main_function.rs @@ -23,7 +23,7 @@ use crate::{ OutputBytes, }; -use leo_asg::{Expression, FunctionBody}; +use leo_asg::{Expression, FunctionBody, FunctionQualifier}; use leo_ast::Input; use std::sync::Arc; @@ -44,47 +44,45 @@ impl> ConstrainedProgram { 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()); if function.function.has_input { - let value = self.allocate_input_keyword(cs, keyword, input)?; + // let input_var = function.scope. + let variable = function.scope.borrow().resolve_variable("input").expect("no input variable in scope when function is qualified"); - self.store(new_scope(&function_name, "input"), value); - } - - - 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)?; + let value = self.allocate_input_keyword(cs, function.function.name.borrow().span.clone(), input)?; - (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)?; - - (input_model.identifier, input_value) - } - }; + self.store(variable.borrow().id.clone(), 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); + match function.function.qualifier { + FunctionQualifier::SelfRef | FunctionQualifier::MutSelfRef => unimplemented!("cannot access self variable in main function"), + FunctionQualifier::Static => (), + } - input_variables.push(Expression::Identifier(input_id)); + 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.clone(), 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(); - let result_value = self.enforce_function(cs, scope, &function_name, function, input_variables, "")?; + let span = function.span.clone().unwrap_or_default(); + let result_value = self.enforce_function(cs, scope, &function_name, function, None, &arguments)?; let output_bytes = OutputBytes::new_from_constrained_value(registers, result_value, span)?; Ok(output_bytes) diff --git a/compiler/src/function/result/result.rs b/compiler/src/function/result/result.rs index 81aa93b55b..e4ca80cdc6 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,20 @@ 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() { - 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 +63,9 @@ 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/store/import.rs b/compiler/src/import/store/import.rs index 37f8206505..221d553c57 100644 --- a/compiler/src/import/store/import.rs +++ b/compiler/src/import/store/import.rs @@ -46,9 +46,6 @@ impl> ConstrainedProgram { .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)?; } diff --git a/compiler/src/program/program.rs b/compiler/src/program/program.rs index e97ac49370..55c15841b8 100644 --- a/compiler/src/program/program.rs +++ b/compiler/src/program/program.rs @@ -21,15 +21,18 @@ use crate::{value::ConstrainedValue, GroupType}; use snarkvm_models::curves::{Field, PrimeField}; use indexmap::IndexMap; +use uuid::Uuid; pub struct ConstrainedProgram> { - pub identifiers: IndexMap>, + identifiers: IndexMap>, + pub self_alias: Option<(Uuid, Uuid)>, // current self id -> id that self resolves to } impl> Default for ConstrainedProgram { fn default() -> Self { Self { identifiers: IndexMap::new(), + self_alias: None, } } } @@ -47,15 +50,30 @@ impl> ConstrainedProgram { Self::default() } - pub(crate) fn store(&mut self, name: String, value: ConstrainedValue) { + pub(crate) fn store(&mut self, name: Uuid, value: ConstrainedValue) { + if let Some((from, _)) = &self.self_alias { + if &name == from { + panic!("attempted to assign to self alias"); + } + } self.identifiers.insert(name, value); } - pub(crate) fn get(&self, name: &str) -> Option<&ConstrainedValue> { + pub(crate) fn get(&self, name: &Uuid) -> Option<&ConstrainedValue> { + if let Some((from, to)) = &self.self_alias { + if name == from { + return self.identifiers.get(to) + } + } 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> { + if let Some((from, to)) = &self.self_alias { + if name == from { + return self.identifiers.get_mut(to); + } + } self.identifiers.get_mut(name) } } diff --git a/compiler/src/statement/assign/assign.rs b/compiler/src/statement/assign/assign.rs index da95bde369..dbb2b66f94 100644 --- a/compiler/src/statement/assign/assign.rs +++ b/compiler/src/statement/assign/assign.rs @@ -19,12 +19,11 @@ use crate::{ arithmetic::*, errors::StatementError, - new_scope, program::ConstrainedProgram, value::ConstrainedValue, GroupType, }; -use leo_ast::{AssignOperation, AssignStatement, AssigneeAccess, Span}; +use leo_asg::{AssignOperation, AssignStatement, Span}; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -41,26 +40,22 @@ impl> ConstrainedProgram { 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( + let mut new_value = self.enforce_expression(cs, file_scope, function_scope, &statement.value)?; + let mut resolved_assignee = self.resolve_assign( cs, file_scope, function_scope, - declared_circuit_reference, mut_self, - statement.assignee.clone(), + 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 +69,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,37 +85,10 @@ impl> ConstrainedProgram { )?; } } - _ => return Err(StatementError::array_assign_range(statement.span)), + _ => return Err(StatementError::array_assign_range(statement.span.clone().unwrap_or_default())), }; } - // 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!(), - } - .clone(); - self.store(self_variable_name, source); - } - } - Ok(()) } @@ -133,8 +101,6 @@ impl> ConstrainedProgram { mut 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 deac8ba26a..7985556dad 100644 --- a/compiler/src/statement/assign/assignee.rs +++ b/compiler/src/statement/assign/assignee.rs @@ -18,13 +18,11 @@ use crate::{ errors::StatementError, - new_scope, - parse_index, program::ConstrainedProgram, value::ConstrainedValue, GroupType, }; -use leo_ast::{Assignee, AssigneeAccess, Identifier, PositiveNumber, Span}; +use leo_asg::{AssignAccess, AssignStatement, Identifier, Span}; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -34,61 +32,55 @@ use snarkvm_models::{ 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 + .as_ref() .map(|start| self.enforce_index(cs, file_scope, function_scope, start, &span)) .transpose()?; let stop_index = stop + .as_ref() .map(|stop| self.enforce_index(cs, file_scope, function_scope, stop, &span)) .transpose()?; Ok(ResolvedAssigneeAccess::ArrayRange(start_index, stop_index)) } - AssigneeAccess::ArrayIndex(index) => { + AssignAccess::ArrayIndex(index) => { let index = self.enforce_index(cs, file_scope, function_scope, 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 { @@ -126,6 +118,7 @@ impl> ConstrainedProgram { } } + // todo: this can prob have most of its error checking removed fn resolve_assignee_access<'a>( access: ResolvedAssigneeAccess, span: &Span, @@ -174,7 +167,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)); @@ -195,26 +187,12 @@ impl> ConstrainedProgram { return Err(StatementError::array_assign_interior_index(span.clone())); } match Self::unwrap_mutable(value.remove(0)) { - ConstrainedValue::CircuitExpression(_variable, members) => { + ConstrainedValue::CircuitExpression(_variable, _, members) => { // Modify the circuit variable in place let matched_variable = members.iter_mut().find(|member| member.0 == name); 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]), }, None => { @@ -232,25 +210,4 @@ impl> ConstrainedProgram { } } } - - 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/block/block.rs b/compiler/src/statement/block/block.rs index 68fdb6177c..2b0740c0d6 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}, @@ -34,22 +34,18 @@ impl> ConstrainedProgram { file_scope: &str, function_scope: &str, indicator: &Boolean, - block: Block, - return_type: Option, - declared_circuit_reference: &str, + block: &BlockStatement, mut_self: bool, ) -> 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() { + for statement in block.statements.iter() { let value = self.enforce_statement( cs, file_scope, function_scope, indicator, statement, - return_type.clone(), - declared_circuit_reference, mut_self, )?; diff --git a/compiler/src/statement/conditional/conditional.rs b/compiler/src/statement/conditional/conditional.rs index 1dd761da5d..242b0c648e 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}, @@ -50,13 +50,11 @@ impl> ConstrainedProgram { 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; @@ -65,14 +63,13 @@ impl> ConstrainedProgram { cs, file_scope, function_scope, - Some(Type::Boolean), - statement.condition.clone(), + &statement.condition, )? { ConstrainedValue::Boolean(resolved) => resolved, value => { return Err(StatementError::conditional_boolean( value.to_string(), - statement.span.clone(), + span, )); } }; @@ -88,25 +85,23 @@ impl> ConstrainedProgram { &mut cs.ns(|| { format!( "branch 1 {} {}:{}", - statement_string, &statement.span.line, &statement.span.start + 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( + let mut branch_1_result = self.enforce_statement( cs, file_scope, function_scope, &branch_1_indicator, - statement.block, - return_type.clone(), - declared_circuit_reference, + &statement.result, mut_self, )?; @@ -119,24 +114,21 @@ 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 { + 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, + next, mut_self, )?, None => vec![], diff --git a/compiler/src/statement/definition/definition.rs b/compiler/src/statement/definition/definition.rs index 326ee69276..dd08f6681c 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}, @@ -29,21 +29,12 @@ impl> ConstrainedProgram { &mut self, cs: &mut CS, function_scope: &str, - is_constant: bool, - variable_name: VariableName, + variable: &Variable, 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); + self.store_definition(function_scope, variable, value); Ok(()) } @@ -52,8 +43,7 @@ impl> ConstrainedProgram { &mut self, cs: &mut CS, function_scope: &str, - is_constant: bool, - variable_names: Vec, + variable_names: &Vec, values: Vec>, span: &Span, ) -> Result<(), StatementError> { @@ -66,7 +56,7 @@ 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)?; + self.enforce_single_definition(cs, function_scope, variable, value, span)?; } Ok(()) @@ -78,36 +68,30 @@ impl> ConstrainedProgram { 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 num_variables = statement.variables.len(); let expression = - self.enforce_expression(cs, file_scope, function_scope, statement.type_.clone(), statement.value)?; + self.enforce_expression(cs, file_scope, function_scope, &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.enforce_single_definition(cs, function_scope, statement.variables.get(0).unwrap(), expression, &span) } 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.clone())), }; self.enforce_multiple_definition( cs, function_scope, - is_constant, - statement.variable_names, + &statement.variables, values, - &statement.span, + &span, ) } } diff --git a/compiler/src/statement/iteration/iteration.rs b/compiler/src/statement/iteration/iteration.rs index c446029368..9fb3d1c9d9 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}, @@ -43,37 +42,34 @@ impl> ConstrainedProgram { 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, file_scope, function_scope, &statement.start, &span)?; + let to = self.enforce_index(cs, file_scope, function_scope, &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.clone(), 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, + &statement.body, mut_self, )?; diff --git a/compiler/src/statement/return_/return_.rs b/compiler/src/statement/return_/return_.rs index bb2450350d..81e54b234a 100644 --- a/compiler/src/statement/return_/return_.rs +++ b/compiler/src/statement/return_/return_.rs @@ -17,49 +17,27 @@ //! 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, + &statement.expression, )?; - - // Make sure we return the correct type. - if let Some(expected) = return_type { - check_return_type(&expected, &result.to_type(&statement.span)?, &statement.span)?; - } - Ok(result) } } diff --git a/compiler/src/statement/statement.rs b/compiler/src/statement/statement.rs index b97235d226..ee97f4e7ee 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}, @@ -42,18 +43,16 @@ impl> ConstrainedProgram { file_scope: &str, function_scope: &str, indicator: &Boolean, - statement: Statement, - return_type: Option, - declared_circuit_reference: &str, + statement: &Arc, mut_self: bool, ) -> 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)?, + self.enforce_return_statement(cs, file_scope, function_scope, statement)?, ); results.push(return_value); @@ -66,7 +65,6 @@ impl> ConstrainedProgram { cs, file_scope, function_scope, - declared_circuit_reference, indicator, mut_self, statement, @@ -78,8 +76,6 @@ impl> ConstrainedProgram { file_scope, function_scope, indicator, - return_type, - declared_circuit_reference, mut_self, statement, )?; @@ -92,8 +88,6 @@ impl> ConstrainedProgram { file_scope, function_scope, indicator, - return_type, - declared_circuit_reference, mut_self, statement, )?; @@ -104,8 +98,7 @@ impl> ConstrainedProgram { self.evaluate_console_function_call(cs, file_scope, function_scope, 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, file_scope, function_scope, &statement.expression)?; // handle empty return value cases match &value { ConstrainedValue::Tuple(values) => { @@ -113,19 +106,17 @@ impl> ConstrainedProgram { results.push((*indicator, value)); } } - _ => return Err(StatementError::unassigned(expression_string, statement.span)), + _ => return Err(StatementError::unassigned(statement.span.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, )?; diff --git a/compiler/src/value/group/group_type.rs b/compiler/src/value/group/group_type.rs index 00ebc44f9c..04df948889 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 d1cbd7c06f..e47e13b87c 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,10 @@ 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 0102d859ac..7479bb3140 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,58 +134,58 @@ 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: &String, 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.clone(), 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(); + let span = span.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)), @@ -283,7 +283,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/integer/integer.rs b/compiler/src/value/integer/integer.rs index c9f2323275..f5962e371c 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_ast::{InputValue}; +use leo_asg::{ConstInt, IntegerType, Span}; use leo_gadgets::{ arithmetic::*, bits::comparator::{ComparatorGadget, EvaluateLtGadget}, @@ -73,111 +74,20 @@ 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, + value: &ConstInt, 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))) - } + ) -> 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)), } } diff --git a/compiler/src/value/value.rs b/compiler/src/value/value.rs index 20337e75c2..6b0b0c2e50 100644 --- a/compiler/src/value/value.rs +++ b/compiler/src/value/value.rs @@ -17,16 +17,14 @@ //! 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, + boolean::input::{allocate_bool}, + errors::{FieldError, ValueError}, Address, FieldType, GroupType, Integer, }; -use leo_asg::{CircuitBody, FunctionBody, GroupValue, Identifier, Span, Type}; +use leo_asg::{CircuitBody, Identifier, Span, Type}; use leo_core::Value; use snarkvm_errors::gadgets::SynthesisError; @@ -39,6 +37,7 @@ use snarkvm_models::{ }; use std::fmt; use std::sync::Arc; +use uuid::Uuid; #[derive(Clone, PartialEq, Eq)] pub struct ConstrainedCircuitMember>(pub Identifier, pub ConstrainedValue); @@ -59,45 +58,13 @@ pub enum ConstrainedValue> { Tuple(Vec>), // Circuits - CircuitDefinition(Arc), - CircuitExpression(Arc, Vec>), - - // Functions - Function(Option, Arc), // (optional circuit identifier, function definition) + CircuitExpression(Arc, Uuid, Vec>), // Modifiers Mutable(Box>), - Static(Box>), - Unresolved(String), } 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, - ))?)), - Type::Integer(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 { @@ -124,7 +91,7 @@ impl> ConstrainedValue { Type::Tuple(types) } - ConstrainedValue::CircuitExpression(id, _members) => Type::Circuit(id.circuit.clone()), + ConstrainedValue::CircuitExpression(id, _, _members) => Type::Circuit(id.circuit.clone()), ConstrainedValue::Mutable(value) => return value.to_type(span), value => return Err(ValueError::implicit(value.to_string(), span.to_owned())), }) @@ -161,61 +128,6 @@ impl> ConstrainedValue { } } - 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, Arc), 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.clone())) - } - value => Err(ExpressionError::undefined_function(value.to_string(), span.to_owned())), - } - } - - pub(crate) fn extract_circuit(&self, span: &Span) -> Result, ExpressionError> { - match self { - ConstrainedValue::CircuitDefinition(circuit) => Ok(circuit.clone()), - 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. /// @@ -280,7 +192,7 @@ impl> ConstrainedValue { value.allocate_value(cs.ns(|| unique_name), span) })?; } - ConstrainedValue::CircuitExpression(_id, members) => { + ConstrainedValue::CircuitExpression(_id, _, members) => { members.iter_mut().enumerate().try_for_each(|(i, member)| { let unique_name = format!("allocate circuit member {} {}:{}", i, span.line, span.start); @@ -290,18 +202,6 @@ impl> ConstrainedValue { 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(_, _) => {} - - // Cannot allocate an unresolved value - ConstrainedValue::Unresolved(value) => { - return Err(ValueError::implicit(value.to_string(), span.to_owned())); - } } Ok(()) @@ -341,7 +241,7 @@ impl> fmt::Display for ConstrainedValue { + ConstrainedValue::CircuitExpression(ref circuit, _, ref members) => { write!(f, "{} {{", circuit.circuit.name.borrow())?; for (i, member) in members.iter().enumerate() { write!(f, "{}: {}", member.0, member.1)?; @@ -351,13 +251,7 @@ impl> fmt::Display for ConstrainedValue write!(f, "circuit {{ {} }}", circuit.circuit.name.borrow().name), - ConstrainedValue::Function(ref _circuit_option, ref function) => { - write!(f, "function {{ {}() }}", function.function.name.borrow().name) - } ConstrainedValue::Mutable(ref value) => write!(f, "{}", value), - ConstrainedValue::Static(ref value) => write!(f, "{}", value), - ConstrainedValue::Unresolved(ref value) => write!(f, "{}", value), } } } @@ -463,14 +357,9 @@ 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), + ConstrainedValue::CircuitExpression(identifier, _, members_1), + ConstrainedValue::CircuitExpression(_identifier, _, members_2), ) => { let mut members = Vec::with_capacity(members_1.len()); @@ -483,12 +372,7 @@ 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::CircuitExpression(identifier.clone(), Uuid::new_v4(), members) } (ConstrainedValue::Mutable(first), _) => Self::conditionally_select(cs, cond, first, second)?, (_, ConstrainedValue::Mutable(second)) => Self::conditionally_select(cs, cond, first, second)?,