mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-11-28 01:01:53 +03:00
Merge pull request #597 from AleoHQ/asg-compiler
[Feature] Abstract Semantic Graph (ASG) - Compiler Integration
This commit is contained in:
commit
2657c448a0
49
Cargo.lock
generated
49
Cargo.lock
generated
@ -1266,16 +1266,14 @@ dependencies = [
|
|||||||
"bincode",
|
"bincode",
|
||||||
"hex",
|
"hex",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
|
"leo-asg",
|
||||||
"leo-ast",
|
"leo-ast",
|
||||||
"leo-core",
|
|
||||||
"leo-gadgets",
|
"leo-gadgets",
|
||||||
"leo-grammar",
|
"leo-grammar",
|
||||||
"leo-imports",
|
"leo-imports",
|
||||||
"leo-input",
|
"leo-input",
|
||||||
"leo-package",
|
"leo-package",
|
||||||
"leo-state",
|
"leo-state",
|
||||||
"leo-symbol-table",
|
|
||||||
"leo-type-inference",
|
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
"pest",
|
"pest",
|
||||||
"rand",
|
"rand",
|
||||||
@ -1292,22 +1290,7 @@ dependencies = [
|
|||||||
"snarkvm-utilities",
|
"snarkvm-utilities",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
"uuid",
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "leo-core"
|
|
||||||
version = "1.0.8"
|
|
||||||
dependencies = [
|
|
||||||
"leo-ast",
|
|
||||||
"leo-gadgets",
|
|
||||||
"rand",
|
|
||||||
"rand_xorshift",
|
|
||||||
"snarkvm-curves",
|
|
||||||
"snarkvm-errors",
|
|
||||||
"snarkvm-gadgets",
|
|
||||||
"snarkvm-models",
|
|
||||||
"snarkvm-utilities",
|
|
||||||
"thiserror",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1344,6 +1327,7 @@ name = "leo-imports"
|
|||||||
version = "1.0.8"
|
version = "1.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
|
"leo-asg",
|
||||||
"leo-ast",
|
"leo-ast",
|
||||||
"leo-grammar",
|
"leo-grammar",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
@ -1438,33 +1422,6 @@ dependencies = [
|
|||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "leo-symbol-table"
|
|
||||||
version = "1.0.8"
|
|
||||||
dependencies = [
|
|
||||||
"indexmap",
|
|
||||||
"leo-ast",
|
|
||||||
"leo-core",
|
|
||||||
"leo-grammar",
|
|
||||||
"leo-imports",
|
|
||||||
"serde",
|
|
||||||
"thiserror",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "leo-type-inference"
|
|
||||||
version = "1.0.8"
|
|
||||||
dependencies = [
|
|
||||||
"indexmap",
|
|
||||||
"leo-ast",
|
|
||||||
"leo-grammar",
|
|
||||||
"leo-imports",
|
|
||||||
"leo-symbol-table",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"thiserror",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.81"
|
version = "0.2.81"
|
||||||
|
@ -28,7 +28,6 @@ path = "leo/main.rs"
|
|||||||
members = [
|
members = [
|
||||||
"ast",
|
"ast",
|
||||||
"compiler",
|
"compiler",
|
||||||
"core",
|
|
||||||
"gadgets",
|
"gadgets",
|
||||||
"grammar",
|
"grammar",
|
||||||
"imports",
|
"imports",
|
||||||
@ -37,8 +36,6 @@ members = [
|
|||||||
"package",
|
"package",
|
||||||
"state",
|
"state",
|
||||||
"asg",
|
"asg",
|
||||||
"symbol-table",
|
|
||||||
"type-inference"
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[dependencies.leo-ast]
|
[dependencies.leo-ast]
|
||||||
|
@ -88,10 +88,6 @@ impl Identifier {
|
|||||||
pub fn is_self(&self) -> bool {
|
pub fn is_self(&self) -> bool {
|
||||||
self.is_self_type() || self.name == "self"
|
self.is_self_type() || self.name == "self"
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_core(&self) -> bool {
|
|
||||||
self.name.starts_with('#')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast> From<GrammarIdentifier<'ast>> for Identifier {
|
impl<'ast> From<GrammarIdentifier<'ast>> for Identifier {
|
||||||
|
@ -21,10 +21,6 @@ edition = "2018"
|
|||||||
path = "../ast"
|
path = "../ast"
|
||||||
version = "1.0.8"
|
version = "1.0.8"
|
||||||
|
|
||||||
[dependencies.leo-core]
|
|
||||||
path = "../core"
|
|
||||||
version = "1.0.8"
|
|
||||||
|
|
||||||
[dependencies.leo-gadgets]
|
[dependencies.leo-gadgets]
|
||||||
path = "../gadgets"
|
path = "../gadgets"
|
||||||
version = "1.0.8"
|
version = "1.0.8"
|
||||||
@ -49,12 +45,8 @@ version = "1.0.8"
|
|||||||
path = "../state"
|
path = "../state"
|
||||||
version = "1.0.8"
|
version = "1.0.8"
|
||||||
|
|
||||||
[dependencies.leo-symbol-table]
|
[dependencies.leo-asg]
|
||||||
path = "../symbol-table"
|
path = "../asg"
|
||||||
version = "1.0.8"
|
|
||||||
|
|
||||||
[dependencies.leo-type-inference]
|
|
||||||
path = "../type-inference"
|
|
||||||
version = "1.0.8"
|
version = "1.0.8"
|
||||||
|
|
||||||
[dependencies.snarkvm-curves]
|
[dependencies.snarkvm-curves]
|
||||||
@ -116,6 +108,10 @@ version = "1.0"
|
|||||||
[dependencies.tracing]
|
[dependencies.tracing]
|
||||||
version = "0.1"
|
version = "0.1"
|
||||||
|
|
||||||
|
[dependencies.uuid]
|
||||||
|
version = "0.8"
|
||||||
|
features = ["v4", "serde"]
|
||||||
|
|
||||||
[dev-dependencies.num-bigint]
|
[dev-dependencies.num-bigint]
|
||||||
version = "0.3"
|
version = "0.3"
|
||||||
|
|
||||||
|
@ -25,13 +25,11 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use leo_ast::{Ast, Input, MainInput, Program};
|
use leo_ast::{Ast, Input, MainInput, Program};
|
||||||
use leo_grammar::Grammar;
|
use leo_grammar::Grammar;
|
||||||
use leo_imports::ImportParser;
|
|
||||||
use leo_input::LeoInputParser;
|
use leo_input::LeoInputParser;
|
||||||
use leo_package::inputs::InputPairs;
|
use leo_package::inputs::InputPairs;
|
||||||
use leo_state::verify_local_data_commitment;
|
use leo_state::verify_local_data_commitment;
|
||||||
use leo_symbol_table::SymbolTable;
|
|
||||||
use leo_type_inference::TypeInference;
|
|
||||||
|
|
||||||
|
use leo_asg::Program as AsgProgram;
|
||||||
use snarkvm_dpc::{base_dpc::instantiated::Components, SystemParameters};
|
use snarkvm_dpc::{base_dpc::instantiated::Components, SystemParameters};
|
||||||
use snarkvm_errors::gadgets::SynthesisError;
|
use snarkvm_errors::gadgets::SynthesisError;
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
@ -54,7 +52,7 @@ pub struct Compiler<F: Field + PrimeField, G: GroupType<F>> {
|
|||||||
output_directory: PathBuf,
|
output_directory: PathBuf,
|
||||||
program: Program,
|
program: Program,
|
||||||
program_input: Input,
|
program_input: Input,
|
||||||
imported_programs: ImportParser,
|
asg: Option<AsgProgram>,
|
||||||
_engine: PhantomData<F>,
|
_engine: PhantomData<F>,
|
||||||
_group: PhantomData<G>,
|
_group: PhantomData<G>,
|
||||||
}
|
}
|
||||||
@ -70,7 +68,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
|||||||
output_directory,
|
output_directory,
|
||||||
program: Program::new(package_name),
|
program: Program::new(package_name),
|
||||||
program_input: Input::new(),
|
program_input: Input::new(),
|
||||||
imported_programs: ImportParser::default(),
|
asg: None,
|
||||||
_engine: PhantomData,
|
_engine: PhantomData,
|
||||||
_group: PhantomData,
|
_group: PhantomData,
|
||||||
}
|
}
|
||||||
@ -162,9 +160,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
|||||||
/// Runs program parser and type inference checker consecutively.
|
/// Runs program parser and type inference checker consecutively.
|
||||||
///
|
///
|
||||||
pub(crate) fn parse_and_check_program(&mut self) -> Result<(), CompilerError> {
|
pub(crate) fn parse_and_check_program(&mut self) -> Result<(), CompilerError> {
|
||||||
self.parse_program()?;
|
self.parse_program()
|
||||||
|
|
||||||
self.check_program()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@ -189,38 +185,20 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
|||||||
// Store the main program file.
|
// Store the main program file.
|
||||||
self.program = core_ast.into_repr();
|
self.program = core_ast.into_repr();
|
||||||
|
|
||||||
// Parse and store all programs imported by the main program file.
|
|
||||||
self.imported_programs = ImportParser::parse(&self.program)?;
|
|
||||||
|
|
||||||
tracing::debug!("Program parsing complete\n{:#?}", self.program);
|
tracing::debug!("Program parsing complete\n{:#?}", self.program);
|
||||||
|
|
||||||
|
self.program_asg_generate()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
pub(crate) fn program_asg_generate(&mut self) -> Result<(), CompilerError> {
|
||||||
/// Runs a type check on the program, imports, and input.
|
|
||||||
///
|
|
||||||
/// First, a symbol table of all user defined types is created.
|
|
||||||
/// Second, a type inference check is run on the program - inferring a data type for all implicit types and
|
|
||||||
/// catching type mismatch errors.
|
|
||||||
///
|
|
||||||
pub(crate) fn check_program(&self) -> Result<(), CompilerError> {
|
|
||||||
// Create a new symbol table from the program, imported_programs, and program_input.
|
// Create a new symbol table from the program, imported_programs, and program_input.
|
||||||
let symbol_table =
|
let asg = leo_asg::InnerProgram::new(&self.program, &mut leo_imports::ImportParser::default())?;
|
||||||
SymbolTable::new(&self.program, &self.imported_programs, &self.program_input).map_err(|mut e| {
|
|
||||||
e.set_path(&self.main_file_path);
|
|
||||||
|
|
||||||
e
|
tracing::debug!("ASG generation complete");
|
||||||
})?;
|
|
||||||
|
|
||||||
// Run type inference check on program.
|
self.asg = Some(asg);
|
||||||
TypeInference::new(&self.program, symbol_table).map_err(|mut e| {
|
|
||||||
e.set_path(&self.main_file_path);
|
|
||||||
|
|
||||||
e
|
|
||||||
})?;
|
|
||||||
|
|
||||||
tracing::debug!("Program checks complete");
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -246,17 +224,10 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
|||||||
// Store the main program file.
|
// Store the main program file.
|
||||||
self.program = core_ast.into_repr();
|
self.program = core_ast.into_repr();
|
||||||
|
|
||||||
// Parse and store all programs imported by the main program file.
|
|
||||||
self.imported_programs = ImportParser::parse(&self.program)?;
|
|
||||||
|
|
||||||
// Create a new symbol table from the program, imported programs, and program input.
|
|
||||||
let symbol_table = SymbolTable::new(&self.program, &self.imported_programs, &self.program_input)?;
|
|
||||||
|
|
||||||
// Run type inference check on program.
|
|
||||||
TypeInference::new(&self.program, symbol_table)?;
|
|
||||||
|
|
||||||
tracing::debug!("Program parsing complete\n{:#?}", self.program);
|
tracing::debug!("Program parsing complete\n{:#?}", self.program);
|
||||||
|
|
||||||
|
self.program_asg_generate()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,13 +274,11 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
|||||||
pub fn compile_constraints<CS: ConstraintSystem<F>>(self, cs: &mut CS) -> Result<OutputBytes, CompilerError> {
|
pub fn compile_constraints<CS: ConstraintSystem<F>>(self, cs: &mut CS) -> Result<OutputBytes, CompilerError> {
|
||||||
let path = self.main_file_path;
|
let path = self.main_file_path;
|
||||||
|
|
||||||
generate_constraints::<F, G, CS>(cs, &self.program, &self.program_input, &self.imported_programs).map_err(
|
generate_constraints::<F, G, CS>(cs, self.asg.as_ref().unwrap(), &self.program_input).map_err(|mut error| {
|
||||||
|mut error| {
|
error.set_path(&path);
|
||||||
error.set_path(&path);
|
|
||||||
|
|
||||||
error
|
error
|
||||||
},
|
})
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@ -317,9 +286,8 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
|||||||
///
|
///
|
||||||
pub fn compile_test_constraints(self, input_pairs: InputPairs) -> Result<(u32, u32), CompilerError> {
|
pub fn compile_test_constraints(self, input_pairs: InputPairs) -> Result<(u32, u32), CompilerError> {
|
||||||
generate_test_constraints::<F, G>(
|
generate_test_constraints::<F, G>(
|
||||||
self.program,
|
self.asg.as_ref().unwrap(),
|
||||||
input_pairs,
|
input_pairs,
|
||||||
&self.imported_programs,
|
|
||||||
&self.main_file_path,
|
&self.main_file_path,
|
||||||
&self.output_directory,
|
&self.output_directory,
|
||||||
)
|
)
|
||||||
@ -333,12 +301,10 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
|||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
) -> Result<OutputBytes, CompilerError> {
|
) -> Result<OutputBytes, CompilerError> {
|
||||||
let path = &self.main_file_path;
|
let path = &self.main_file_path;
|
||||||
generate_constraints::<_, G, _>(cs, &self.program, &self.program_input, &self.imported_programs).map_err(
|
generate_constraints::<_, G, _>(cs, self.asg.as_ref().unwrap(), &self.program_input).map_err(|mut error| {
|
||||||
|mut error| {
|
error.set_path(&path);
|
||||||
error.set_path(&path);
|
error
|
||||||
error
|
})
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,8 @@ use crate::{
|
|||||||
value::ConstrainedValue,
|
value::ConstrainedValue,
|
||||||
GroupType,
|
GroupType,
|
||||||
};
|
};
|
||||||
use leo_ast::{Expression, Span, Type};
|
use leo_asg::{Expression, Span};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
@ -34,17 +35,12 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
pub fn evaluate_console_assert<CS: ConstraintSystem<F>>(
|
pub fn evaluate_console_assert<CS: ConstraintSystem<F>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: &str,
|
|
||||||
function_scope: &str,
|
|
||||||
indicator: &Boolean,
|
indicator: &Boolean,
|
||||||
expression: Expression,
|
expression: &Arc<Expression>,
|
||||||
span: &Span,
|
span: &Span,
|
||||||
) -> Result<(), ConsoleError> {
|
) -> Result<(), ConsoleError> {
|
||||||
let expected_type = Some(Type::Boolean);
|
|
||||||
let expression_string = expression.to_string();
|
|
||||||
|
|
||||||
// Evaluate assert expression
|
// Evaluate assert expression
|
||||||
let assert_expression = self.enforce_expression(cs, file_scope, function_scope, expected_type, expression)?;
|
let assert_expression = self.enforce_expression(cs, expression)?;
|
||||||
|
|
||||||
// If the indicator bit is false, do not evaluate the assertion
|
// If the indicator bit is false, do not evaluate the assertion
|
||||||
// This is okay since we are not enforcing any constraints
|
// This is okay since we are not enforcing any constraints
|
||||||
@ -57,7 +53,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
ConstrainedValue::Boolean(boolean) => boolean.get_value(),
|
ConstrainedValue::Boolean(boolean) => boolean.get_value(),
|
||||||
_ => {
|
_ => {
|
||||||
return Err(ConsoleError::assertion_must_be_boolean(
|
return Err(ConsoleError::assertion_must_be_boolean(
|
||||||
expression_string,
|
span.text.clone(),
|
||||||
span.to_owned(),
|
span.to_owned(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -65,7 +61,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
let result_bool = result_option.ok_or_else(|| ConsoleError::assertion_depends_on_input(span.to_owned()))?;
|
let result_bool = result_option.ok_or_else(|| ConsoleError::assertion_depends_on_input(span.to_owned()))?;
|
||||||
|
|
||||||
if !result_bool {
|
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(())
|
Ok(())
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
//! Evaluates a macro in a compiled Leo program.
|
//! Evaluates a macro in a compiled Leo program.
|
||||||
|
|
||||||
use crate::{errors::ConsoleError, program::ConstrainedProgram, statement::get_indicator_value, GroupType};
|
use crate::{errors::ConsoleError, program::ConstrainedProgram, statement::get_indicator_value, GroupType};
|
||||||
use leo_ast::{ConsoleFunction, ConsoleStatement};
|
use leo_asg::{ConsoleFunction, ConsoleStatement};
|
||||||
|
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
@ -28,31 +28,29 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
pub fn evaluate_console_function_call<CS: ConstraintSystem<F>>(
|
pub fn evaluate_console_function_call<CS: ConstraintSystem<F>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: &str,
|
|
||||||
function_scope: &str,
|
|
||||||
indicator: &Boolean,
|
indicator: &Boolean,
|
||||||
console: ConsoleStatement,
|
console: &ConsoleStatement,
|
||||||
) -> Result<(), ConsoleError> {
|
) -> Result<(), ConsoleError> {
|
||||||
match console.function {
|
match &console.function {
|
||||||
ConsoleFunction::Assert(expression) => {
|
ConsoleFunction::Assert(expression) => {
|
||||||
self.evaluate_console_assert(cs, file_scope, function_scope, indicator, expression, &console.span)?;
|
self.evaluate_console_assert(cs, indicator, expression, &console.span.clone().unwrap_or_default())?;
|
||||||
}
|
}
|
||||||
ConsoleFunction::Debug(string) => {
|
ConsoleFunction::Debug(string) => {
|
||||||
let string = self.format(cs, file_scope, function_scope, string)?;
|
let string = self.format(cs, string)?;
|
||||||
|
|
||||||
if get_indicator_value(indicator) {
|
if get_indicator_value(indicator) {
|
||||||
tracing::debug!("{}", string);
|
tracing::debug!("{}", string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ConsoleFunction::Error(string) => {
|
ConsoleFunction::Error(string) => {
|
||||||
let string = self.format(cs, file_scope, function_scope, string)?;
|
let string = self.format(cs, string)?;
|
||||||
|
|
||||||
if get_indicator_value(indicator) {
|
if get_indicator_value(indicator) {
|
||||||
tracing::error!("{}", string);
|
tracing::error!("{}", string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ConsoleFunction::Log(string) => {
|
ConsoleFunction::Log(string) => {
|
||||||
let string = self.format(cs, file_scope, function_scope, string)?;
|
let string = self.format(cs, string)?;
|
||||||
|
|
||||||
if get_indicator_value(indicator) {
|
if get_indicator_value(indicator) {
|
||||||
tracing::info!("{}", string);
|
tracing::info!("{}", string);
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
//! Evaluates a formatted string in a compiled Leo program.
|
//! Evaluates a formatted string in a compiled Leo program.
|
||||||
|
|
||||||
use crate::{errors::ConsoleError, program::ConstrainedProgram, GroupType};
|
use crate::{errors::ConsoleError, program::ConstrainedProgram, GroupType};
|
||||||
use leo_ast::FormattedString;
|
use leo_asg::FormattedString;
|
||||||
|
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
@ -28,16 +28,14 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
pub fn format<CS: ConstraintSystem<F>>(
|
pub fn format<CS: ConstraintSystem<F>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: &str,
|
formatted: &FormattedString,
|
||||||
function_scope: &str,
|
|
||||||
formatted: FormattedString,
|
|
||||||
) -> Result<String, ConsoleError> {
|
) -> Result<String, ConsoleError> {
|
||||||
// Check that containers and parameters match
|
// Check that containers and parameters match
|
||||||
if formatted.containers.len() != formatted.parameters.len() {
|
if formatted.containers.len() != formatted.parameters.len() {
|
||||||
return Err(ConsoleError::length(
|
return Err(ConsoleError::length(
|
||||||
formatted.containers.len(),
|
formatted.containers.len(),
|
||||||
formatted.parameters.len(),
|
formatted.parameters.len(),
|
||||||
formatted.span,
|
formatted.span.clone(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,8 +49,8 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
// Insert the parameter for each container `{}`
|
// Insert the parameter for each container `{}`
|
||||||
let mut result = string.to_string();
|
let mut result = string.to_string();
|
||||||
|
|
||||||
for parameter in formatted.parameters.into_iter() {
|
for parameter in formatted.parameters.iter() {
|
||||||
let parameter_value = self.enforce_expression(cs, file_scope, function_scope, None, parameter)?;
|
let parameter_value = self.enforce_expression(cs, parameter)?;
|
||||||
|
|
||||||
result = result.replacen("{}", ¶meter_value.to_string(), 1);
|
result = result.replacen("{}", ¶meter_value.to_string(), 1);
|
||||||
}
|
}
|
||||||
|
@ -16,17 +16,9 @@
|
|||||||
|
|
||||||
//! Generates R1CS constraints for a compiled Leo program.
|
//! Generates R1CS constraints for a compiled Leo program.
|
||||||
|
|
||||||
use crate::{
|
use crate::{errors::CompilerError, ConstrainedProgram, GroupType, OutputBytes, OutputFile};
|
||||||
errors::CompilerError,
|
use leo_asg::Program;
|
||||||
new_scope,
|
use leo_ast::Input;
|
||||||
ConstrainedProgram,
|
|
||||||
ConstrainedValue,
|
|
||||||
GroupType,
|
|
||||||
OutputBytes,
|
|
||||||
OutputFile,
|
|
||||||
};
|
|
||||||
use leo_ast::{Input, Program};
|
|
||||||
use leo_imports::ImportParser;
|
|
||||||
use leo_input::LeoInputParser;
|
use leo_input::LeoInputParser;
|
||||||
use leo_package::inputs::InputPairs;
|
use leo_package::inputs::InputPairs;
|
||||||
|
|
||||||
@ -40,19 +32,17 @@ pub fn generate_constraints<F: Field + PrimeField, G: GroupType<F>, CS: Constrai
|
|||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
program: &Program,
|
program: &Program,
|
||||||
input: &Input,
|
input: &Input,
|
||||||
imported_programs: &ImportParser,
|
|
||||||
) -> Result<OutputBytes, CompilerError> {
|
) -> Result<OutputBytes, CompilerError> {
|
||||||
let mut resolved_program = ConstrainedProgram::<F, G>::new();
|
let mut resolved_program = ConstrainedProgram::<F, G>::new(program.clone());
|
||||||
let program_name = program.get_name();
|
|
||||||
let main_function_name = new_scope(&program_name, "main");
|
|
||||||
|
|
||||||
resolved_program.store_definitions(program, imported_programs)?;
|
let main = {
|
||||||
|
let program = program.borrow();
|
||||||
|
program.functions.get("main").cloned()
|
||||||
|
};
|
||||||
|
|
||||||
let main = resolved_program.get(&main_function_name).ok_or(CompilerError::NoMain)?;
|
match main {
|
||||||
|
Some(function) => {
|
||||||
match main.clone() {
|
let result = resolved_program.enforce_main_function(cs, &function, input)?;
|
||||||
ConstrainedValue::Function(_circuit_identifier, function) => {
|
|
||||||
let result = resolved_program.enforce_main_function(cs, &program_name, *function, input)?;
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
_ => Err(CompilerError::NoMainFunction),
|
_ => Err(CompilerError::NoMainFunction),
|
||||||
@ -60,38 +50,34 @@ pub fn generate_constraints<F: Field + PrimeField, G: GroupType<F>, CS: Constrai
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_test_constraints<F: Field + PrimeField, G: GroupType<F>>(
|
pub fn generate_test_constraints<F: Field + PrimeField, G: GroupType<F>>(
|
||||||
program: Program,
|
program: &Program,
|
||||||
input: InputPairs,
|
input: InputPairs,
|
||||||
imported_programs: &ImportParser,
|
|
||||||
main_file_path: &Path,
|
main_file_path: &Path,
|
||||||
output_directory: &Path,
|
output_directory: &Path,
|
||||||
) -> Result<(u32, u32), CompilerError> {
|
) -> Result<(u32, u32), CompilerError> {
|
||||||
let mut resolved_program = ConstrainedProgram::<F, G>::new();
|
let mut resolved_program = ConstrainedProgram::<F, G>::new(program.clone());
|
||||||
let program_name = program.get_name();
|
let program_name = program.borrow().name.clone();
|
||||||
|
|
||||||
let tests = program.tests.clone();
|
|
||||||
|
|
||||||
// Store definitions
|
|
||||||
resolved_program.store_definitions(&program, imported_programs)?;
|
|
||||||
|
|
||||||
// Get default input
|
// Get default input
|
||||||
let default = input.pairs.get(&program_name);
|
let default = input.pairs.get(&program_name);
|
||||||
|
|
||||||
|
let program = program.borrow();
|
||||||
|
let tests = &program.test_functions;
|
||||||
tracing::info!("Running {} tests", tests.len());
|
tracing::info!("Running {} tests", tests.len());
|
||||||
|
|
||||||
// Count passed and failed tests
|
// Count passed and failed tests
|
||||||
let mut passed = 0;
|
let mut passed = 0;
|
||||||
let mut failed = 0;
|
let mut failed = 0;
|
||||||
|
|
||||||
for (test_name, test) in tests.into_iter() {
|
for (test_name, (function, input_file)) in tests.into_iter() {
|
||||||
let cs = &mut TestConstraintSystem::<F>::new();
|
let cs = &mut TestConstraintSystem::<F>::new();
|
||||||
let full_test_name = format!("{}::{}", program_name.clone(), test_name);
|
let full_test_name = format!("{}::{}", program_name.clone(), test_name);
|
||||||
let mut output_file_name = program_name.clone();
|
let mut output_file_name = program_name.clone();
|
||||||
|
|
||||||
// get input file name from annotation or use test_name
|
// get input file name from annotation or use test_name
|
||||||
let input_pair = match test.input_file {
|
let input_pair = match input_file {
|
||||||
Some(file_id) => {
|
Some(file_id) => {
|
||||||
let file_name = file_id.name;
|
let file_name = file_id.name.clone();
|
||||||
|
|
||||||
output_file_name = file_name.clone();
|
output_file_name = file_name.clone();
|
||||||
|
|
||||||
@ -117,10 +103,7 @@ pub fn generate_test_constraints<F: Field + PrimeField, G: GroupType<F>>(
|
|||||||
|
|
||||||
// run test function on new program with input
|
// run test function on new program with input
|
||||||
let result = resolved_program.enforce_main_function(
|
let result = resolved_program.enforce_main_function(
|
||||||
cs,
|
cs, function, &input, // pass program input into every test
|
||||||
&program_name,
|
|
||||||
test.function,
|
|
||||||
&input, // pass program input into every test
|
|
||||||
);
|
);
|
||||||
|
|
||||||
match (result.is_ok(), cs.is_satisfied()) {
|
match (result.is_ok(), cs.is_satisfied()) {
|
||||||
|
@ -16,30 +16,19 @@
|
|||||||
|
|
||||||
//! Stores all defined names in a compiled Leo program.
|
//! Stores all defined names in a compiled Leo program.
|
||||||
|
|
||||||
use crate::{
|
use crate::{program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
||||||
program::{new_scope, ConstrainedProgram},
|
use leo_asg::Variable;
|
||||||
value::ConstrainedValue,
|
|
||||||
GroupType,
|
|
||||||
};
|
|
||||||
use leo_ast::Identifier;
|
|
||||||
|
|
||||||
use snarkvm_models::curves::{Field, PrimeField};
|
use snarkvm_models::curves::{Field, PrimeField};
|
||||||
|
|
||||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||||
pub fn store_definition(
|
pub fn store_definition(&mut self, variable: &Variable, mut value: ConstrainedValue<F, G>) {
|
||||||
&mut self,
|
let variable = variable.borrow();
|
||||||
function_scope: &str,
|
|
||||||
mutable: bool,
|
|
||||||
identifier: Identifier,
|
|
||||||
mut value: ConstrainedValue<F, G>,
|
|
||||||
) {
|
|
||||||
// Store with given mutability
|
// Store with given mutability
|
||||||
if mutable {
|
if variable.mutable {
|
||||||
value = ConstrainedValue::Mutable(Box::new(value));
|
value = ConstrainedValue::Mutable(Box::new(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
let variable_program_identifier = new_scope(function_scope, &identifier.name);
|
self.store(variable.id, value);
|
||||||
|
|
||||||
self.store(variable_program_identifier, value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
|
||||||
// This file is part of the Leo library.
|
|
||||||
|
|
||||||
// The Leo library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// The Leo library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
//! Stores all defined names in a compiled Leo program.
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
errors::ImportError,
|
|
||||||
program::{new_scope, ConstrainedProgram},
|
|
||||||
value::ConstrainedValue,
|
|
||||||
GroupType,
|
|
||||||
};
|
|
||||||
use leo_ast::Program;
|
|
||||||
use leo_imports::ImportParser;
|
|
||||||
|
|
||||||
use snarkvm_models::curves::{Field, PrimeField};
|
|
||||||
|
|
||||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|
||||||
pub fn store_definitions(
|
|
||||||
&mut self,
|
|
||||||
program: &Program,
|
|
||||||
imported_programs: &ImportParser,
|
|
||||||
) -> Result<(), ImportError> {
|
|
||||||
let program_name = program.name.trim_end_matches(".leo");
|
|
||||||
|
|
||||||
// evaluate all import statements and store imported definitions
|
|
||||||
program
|
|
||||||
.imports
|
|
||||||
.iter()
|
|
||||||
.map(|import| self.store_import(&program_name, import, imported_programs))
|
|
||||||
.collect::<Result<Vec<_>, ImportError>>()?;
|
|
||||||
|
|
||||||
// evaluate and store all circuit definitions
|
|
||||||
program.circuits.iter().for_each(|(identifier, circuit)| {
|
|
||||||
let resolved_circuit_name = new_scope(program_name, &identifier.name);
|
|
||||||
self.store(
|
|
||||||
resolved_circuit_name,
|
|
||||||
ConstrainedValue::CircuitDefinition(circuit.clone()),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// evaluate and store all function definitions
|
|
||||||
program.functions.iter().for_each(|(function_name, function)| {
|
|
||||||
let resolved_function_name = new_scope(program_name, &function_name.name);
|
|
||||||
self.store(
|
|
||||||
resolved_function_name,
|
|
||||||
ConstrainedValue::Function(None, Box::new(function.clone())),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
@ -16,6 +16,3 @@
|
|||||||
|
|
||||||
pub mod definition;
|
pub mod definition;
|
||||||
pub use self::definition::*;
|
pub use self::definition::*;
|
||||||
|
|
||||||
pub mod definitions;
|
|
||||||
pub use self::definitions::*;
|
|
||||||
|
@ -15,13 +15,12 @@
|
|||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::errors::{FunctionError, ImportError, OutputBytesError, OutputFileError};
|
use crate::errors::{FunctionError, ImportError, OutputBytesError, OutputFileError};
|
||||||
|
use leo_asg::AsgConvertError;
|
||||||
use leo_ast::AstError;
|
use leo_ast::AstError;
|
||||||
use leo_grammar::ParserError;
|
use leo_grammar::ParserError;
|
||||||
use leo_imports::ImportParserError;
|
use leo_imports::ImportParserError;
|
||||||
use leo_input::InputParserError;
|
use leo_input::InputParserError;
|
||||||
use leo_state::LocalDataVerificationError;
|
use leo_state::LocalDataVerificationError;
|
||||||
use leo_symbol_table::SymbolTableError;
|
|
||||||
use leo_type_inference::TypeInferenceError;
|
|
||||||
|
|
||||||
use bincode::Error as SerdeError;
|
use bincode::Error as SerdeError;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
@ -74,9 +73,7 @@ pub enum CompilerError {
|
|||||||
SerdeError(#[from] SerdeError),
|
SerdeError(#[from] SerdeError),
|
||||||
|
|
||||||
#[error("{}", _0)]
|
#[error("{}", _0)]
|
||||||
SymbolTableError(#[from] SymbolTableError),
|
AsgConvertError(#[from] AsgConvertError),
|
||||||
#[error("{}", _0)]
|
|
||||||
TypeInferenceError(#[from] TypeInferenceError),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompilerError {
|
impl CompilerError {
|
||||||
@ -85,8 +82,6 @@ impl CompilerError {
|
|||||||
CompilerError::InputParserError(error) => error.set_path(path),
|
CompilerError::InputParserError(error) => error.set_path(path),
|
||||||
CompilerError::FunctionError(error) => error.set_path(path),
|
CompilerError::FunctionError(error) => error.set_path(path),
|
||||||
CompilerError::OutputStringError(error) => error.set_path(path),
|
CompilerError::OutputStringError(error) => error.set_path(path),
|
||||||
CompilerError::SymbolTableError(error) => error.set_path(path),
|
|
||||||
CompilerError::TypeInferenceError(error) => error.set_path(path),
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
use crate::errors::{AddressError, BooleanError, FieldError, FunctionError, GroupError, IntegerError, ValueError};
|
use crate::errors::{AddressError, BooleanError, FieldError, FunctionError, GroupError, IntegerError, ValueError};
|
||||||
use leo_ast::{ArrayDimensions, Error as FormattedError, Identifier, PositiveNumber, Span};
|
use leo_ast::{ArrayDimensions, Error as FormattedError, Identifier, PositiveNumber, Span};
|
||||||
use leo_core::LeoCorePackageError;
|
|
||||||
|
|
||||||
use snarkvm_errors::gadgets::SynthesisError;
|
use snarkvm_errors::gadgets::SynthesisError;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
@ -44,9 +43,6 @@ pub enum ExpressionError {
|
|||||||
#[error("{}", _0)]
|
#[error("{}", _0)]
|
||||||
IntegerError(#[from] IntegerError),
|
IntegerError(#[from] IntegerError),
|
||||||
|
|
||||||
#[error("{}", _0)]
|
|
||||||
LeoCoreError(#[from] LeoCorePackageError),
|
|
||||||
|
|
||||||
#[error("{}", _0)]
|
#[error("{}", _0)]
|
||||||
ValueError(#[from] ValueError),
|
ValueError(#[from] ValueError),
|
||||||
}
|
}
|
||||||
@ -61,7 +57,6 @@ impl ExpressionError {
|
|||||||
ExpressionError::FunctionError(error) => error.set_path(path),
|
ExpressionError::FunctionError(error) => error.set_path(path),
|
||||||
ExpressionError::GroupError(error) => error.set_path(path),
|
ExpressionError::GroupError(error) => error.set_path(path),
|
||||||
ExpressionError::IntegerError(error) => error.set_path(path),
|
ExpressionError::IntegerError(error) => error.set_path(path),
|
||||||
ExpressionError::LeoCoreError(error) => error.set_path(path),
|
|
||||||
ExpressionError::ValueError(error) => error.set_path(path),
|
ExpressionError::ValueError(error) => error.set_path(path),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ use crate::errors::{
|
|||||||
StatementError,
|
StatementError,
|
||||||
ValueError,
|
ValueError,
|
||||||
};
|
};
|
||||||
|
use leo_asg::AsgConvertError;
|
||||||
use leo_ast::{Error as FormattedError, Span};
|
use leo_ast::{Error as FormattedError, Span};
|
||||||
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
@ -60,6 +61,9 @@ pub enum FunctionError {
|
|||||||
|
|
||||||
#[error("{}", _0)]
|
#[error("{}", _0)]
|
||||||
ValueError(#[from] ValueError),
|
ValueError(#[from] ValueError),
|
||||||
|
|
||||||
|
#[error("{}", _0)]
|
||||||
|
ImportASGError(#[from] AsgConvertError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FunctionError {
|
impl FunctionError {
|
||||||
@ -75,6 +79,7 @@ impl FunctionError {
|
|||||||
FunctionError::OutputStringError(error) => error.set_path(path),
|
FunctionError::OutputStringError(error) => error.set_path(path),
|
||||||
FunctionError::StatementError(error) => error.set_path(path),
|
FunctionError::StatementError(error) => error.set_path(path),
|
||||||
FunctionError::ValueError(error) => error.set_path(path),
|
FunctionError::ValueError(error) => error.set_path(path),
|
||||||
|
FunctionError::ImportASGError(_error) => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,15 +15,11 @@
|
|||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use leo_ast::{Error as FormattedError, Identifier, ImportSymbol, Span};
|
use leo_ast::{Error as FormattedError, Identifier, ImportSymbol, Span};
|
||||||
use leo_core::LeoCorePackageError;
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum ImportError {
|
pub enum ImportError {
|
||||||
#[error("{}", _0)]
|
#[error("{}", _0)]
|
||||||
Error(#[from] FormattedError),
|
Error(#[from] FormattedError),
|
||||||
|
|
||||||
#[error("{}", _0)]
|
|
||||||
LeoCoreError(#[from] LeoCorePackageError),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ImportError {
|
impl ImportError {
|
||||||
|
@ -15,7 +15,8 @@
|
|||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::errors::ValueError;
|
use crate::errors::ValueError;
|
||||||
use leo_ast::{Error as FormattedError, Span, Type};
|
use leo_asg::{AsgConvertError, Type};
|
||||||
|
use leo_ast::{Error as FormattedError, Span};
|
||||||
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
@ -26,6 +27,9 @@ pub enum OutputBytesError {
|
|||||||
|
|
||||||
#[error("{}", _0)]
|
#[error("{}", _0)]
|
||||||
ValueError(#[from] ValueError),
|
ValueError(#[from] ValueError),
|
||||||
|
|
||||||
|
#[error("{}", _0)]
|
||||||
|
AsgConvertError(#[from] AsgConvertError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OutputBytesError {
|
impl OutputBytesError {
|
||||||
@ -33,6 +37,7 @@ impl OutputBytesError {
|
|||||||
match self {
|
match self {
|
||||||
OutputBytesError::Error(error) => error.set_path(path),
|
OutputBytesError::Error(error) => error.set_path(path),
|
||||||
OutputBytesError::ValueError(error) => error.set_path(path),
|
OutputBytesError::ValueError(error) => error.set_path(path),
|
||||||
|
OutputBytesError::AsgConvertError(_error) => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,7 +51,7 @@ impl OutputBytesError {
|
|||||||
Self::new_from_span(message, span)
|
Self::new_from_span(message, span)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mismatched_output_types(left: Type, right: Type, span: Span) -> Self {
|
pub fn mismatched_output_types(left: &Type, right: &Type, span: Span) -> Self {
|
||||||
let message = format!(
|
let message = format!(
|
||||||
"Mismatched types. Expected register output type `{}`, found type `{}`.",
|
"Mismatched types. Expected register output type `{}`, found type `{}`.",
|
||||||
left, right
|
left, right
|
||||||
|
@ -15,7 +15,8 @@
|
|||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::errors::{AddressError, BooleanError, ConsoleError, ExpressionError, IntegerError, ValueError};
|
use crate::errors::{AddressError, BooleanError, ConsoleError, ExpressionError, IntegerError, ValueError};
|
||||||
use leo_ast::{Error as FormattedError, Span, Type};
|
use leo_asg::Type;
|
||||||
|
use leo_ast::{Error as FormattedError, Span};
|
||||||
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
@ -166,7 +167,7 @@ impl StatementError {
|
|||||||
Self::new_from_span(message, span)
|
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!(
|
let message = format!(
|
||||||
"function expected `{}` return type but no valid branches returned a result",
|
"function expected `{}` return type but no valid branches returned a result",
|
||||||
expected
|
expected
|
||||||
|
@ -40,14 +40,6 @@ pub fn enforce_add<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<
|
|||||||
(ConstrainedValue::Group(point_1), ConstrainedValue::Group(point_2)) => {
|
(ConstrainedValue::Group(point_1), ConstrainedValue::Group(point_2)) => {
|
||||||
Ok(ConstrainedValue::Group(point_1.add(cs, &point_2, span)?))
|
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(
|
(val_1, val_2) => Err(ExpressionError::incompatible_types(
|
||||||
format!("{} + {}", val_1, val_2),
|
format!("{} + {}", val_1, val_2),
|
||||||
span.to_owned(),
|
span.to_owned(),
|
||||||
|
@ -37,14 +37,6 @@ pub fn enforce_div<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<
|
|||||||
(ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => {
|
(ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => {
|
||||||
Ok(ConstrainedValue::Field(field_1.div(cs, &field_2, span)?))
|
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(
|
(val_1, val_2) => Err(ExpressionError::incompatible_types(
|
||||||
format!("{} / {}", val_1, val_2,),
|
format!("{} / {}", val_1, val_2,),
|
||||||
span.to_owned(),
|
span.to_owned(),
|
||||||
|
@ -37,14 +37,6 @@ pub fn enforce_mul<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<
|
|||||||
(ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => {
|
(ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => {
|
||||||
Ok(ConstrainedValue::Field(field_1.mul(cs, &field_2, span)?))
|
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(
|
(val_1, val_2) => Err(ExpressionError::incompatible_types(
|
||||||
format!("{} * {}", val_1, val_2),
|
format!("{} * {}", val_1, val_2),
|
||||||
span.to_owned(),
|
span.to_owned(),
|
||||||
|
@ -34,14 +34,6 @@ pub fn enforce_pow<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<
|
|||||||
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
||||||
Ok(ConstrainedValue::Integer(num_1.pow(cs, num_2, span)?))
|
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(
|
(val_1, val_2) => Err(ExpressionError::incompatible_types(
|
||||||
format!("{} ** {}", val_1, val_2,),
|
format!("{} ** {}", val_1, val_2,),
|
||||||
span.to_owned(),
|
span.to_owned(),
|
||||||
|
@ -40,14 +40,6 @@ pub fn enforce_sub<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<
|
|||||||
(ConstrainedValue::Group(point_1), ConstrainedValue::Group(point_2)) => {
|
(ConstrainedValue::Group(point_1), ConstrainedValue::Group(point_2)) => {
|
||||||
Ok(ConstrainedValue::Group(point_1.sub(cs, &point_2, span)?))
|
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(
|
(val_1, val_2) => Err(ExpressionError::incompatible_types(
|
||||||
format!("{} - {}", val_1, val_2),
|
format!("{} - {}", val_1, val_2),
|
||||||
span.to_owned(),
|
span.to_owned(),
|
||||||
|
@ -17,7 +17,8 @@
|
|||||||
//! Enforces array access in a compiled Leo program.
|
//! Enforces array access in a compiled Leo program.
|
||||||
|
|
||||||
use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
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::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
@ -29,19 +30,16 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
pub fn enforce_array_access<CS: ConstraintSystem<F>>(
|
pub fn enforce_array_access<CS: ConstraintSystem<F>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: &str,
|
array: &Arc<Expression>,
|
||||||
function_scope: &str,
|
index: &Arc<Expression>,
|
||||||
expected_type: Option<Type>,
|
|
||||||
array: Expression,
|
|
||||||
index: Expression,
|
|
||||||
span: &Span,
|
span: &Span,
|
||||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||||
let array = match self.enforce_operand(cs, file_scope, function_scope, expected_type, array, span)? {
|
let array = match self.enforce_operand(cs, array)? {
|
||||||
ConstrainedValue::Array(array) => array,
|
ConstrainedValue::Array(array) => array,
|
||||||
value => return Err(ExpressionError::undefined_array(value.to_string(), span.to_owned())),
|
value => return Err(ExpressionError::undefined_array(value.to_string(), span.to_owned())),
|
||||||
};
|
};
|
||||||
|
|
||||||
let index_resolved = self.enforce_index(cs, file_scope, function_scope, index, span)?;
|
let index_resolved = self.enforce_index(cs, index, span)?;
|
||||||
Ok(array[index_resolved].to_owned())
|
Ok(array[index_resolved].to_owned())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,25 +47,22 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
pub fn enforce_array_range_access<CS: ConstraintSystem<F>>(
|
pub fn enforce_array_range_access<CS: ConstraintSystem<F>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: &str,
|
array: &Arc<Expression>,
|
||||||
function_scope: &str,
|
left: Option<&Arc<Expression>>,
|
||||||
expected_type: Option<Type>,
|
right: Option<&Arc<Expression>>,
|
||||||
array: Expression,
|
|
||||||
left: Option<Expression>,
|
|
||||||
right: Option<Expression>,
|
|
||||||
span: &Span,
|
span: &Span,
|
||||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||||
let array = match self.enforce_operand(cs, file_scope, function_scope, expected_type, array, span)? {
|
let array = match self.enforce_operand(cs, array)? {
|
||||||
ConstrainedValue::Array(array) => array,
|
ConstrainedValue::Array(array) => array,
|
||||||
value => return Err(ExpressionError::undefined_array(value.to_string(), span.to_owned())),
|
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)?,
|
Some(from_index) => self.enforce_index(cs, from_index, span)?,
|
||||||
None => 0usize, // Array slice starts at index 0
|
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)?,
|
Some(to_index) => self.enforce_index(cs, to_index, span)?,
|
||||||
None => array.len(), // Array slice ends at array length
|
None => array.len(), // Array slice ends at array length
|
||||||
};
|
};
|
||||||
Ok(ConstrainedValue::Array(array[from_resolved..to_resolved].to_owned()))
|
Ok(ConstrainedValue::Array(array[from_resolved..to_resolved].to_owned()))
|
||||||
|
@ -16,13 +16,9 @@
|
|||||||
|
|
||||||
//! Enforces an array expression in a compiled Leo program.
|
//! Enforces an array expression in a compiled Leo program.
|
||||||
|
|
||||||
use crate::{
|
use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
||||||
errors::ExpressionError,
|
use leo_asg::{Expression, Span};
|
||||||
program::{new_scope, ConstrainedProgram},
|
use std::sync::Arc;
|
||||||
value::ConstrainedValue,
|
|
||||||
GroupType,
|
|
||||||
};
|
|
||||||
use leo_ast::{ArrayDimensions, Expression, PositiveNumber, Span, SpreadOrExpression, Type};
|
|
||||||
|
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
@ -34,65 +30,21 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
pub fn enforce_array<CS: ConstraintSystem<F>>(
|
pub fn enforce_array<CS: ConstraintSystem<F>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: &str,
|
array: &[(Arc<Expression>, bool)],
|
||||||
function_scope: &str,
|
|
||||||
mut expected_type: Option<Type>,
|
|
||||||
array: Vec<SpreadOrExpression>,
|
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||||
let mut expected_dimension = None;
|
let 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![];
|
let mut result = vec![];
|
||||||
for element in array.into_iter() {
|
for (element, is_spread) in array.iter() {
|
||||||
match element {
|
let element_value = self.enforce_expression(cs, element)?;
|
||||||
SpreadOrExpression::Spread(spread) => match spread {
|
if *is_spread {
|
||||||
Expression::Identifier(identifier) => {
|
match element_value {
|
||||||
let array_name = new_scope(&function_scope, &identifier.name);
|
ConstrainedValue::Array(array) => result.extend(array),
|
||||||
match self.get(&array_name) {
|
_ => unimplemented!(), // type should already be checked
|
||||||
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,
|
|
||||||
)?);
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
result.push(element_value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,144 +66,17 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
pub fn enforce_array_initializer<CS: ConstraintSystem<F>>(
|
pub fn enforce_array_initializer<CS: ConstraintSystem<F>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: &str,
|
element_expression: &Arc<Expression>,
|
||||||
function_scope: &str,
|
actual_size: usize,
|
||||||
expected_type: Option<Type>,
|
|
||||||
element_expression: Expression,
|
|
||||||
mut actual_dimensions: ArrayDimensions,
|
|
||||||
span: Span,
|
|
||||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||||
// Compare dimensions
|
let mut value = self.enforce_expression(cs, element_expression)?;
|
||||||
// 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 {
|
// Allocate the array.
|
||||||
if expected_dimensions == actual_dimensions {
|
let array = vec![value; actual_size];
|
||||||
// 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.
|
// Set the array value.
|
||||||
while let Some(dimension) = actual_dimensions.remove_last() {
|
value = ConstrainedValue::Array(array);
|
||||||
// Parse the dimension into a `usize`.
|
|
||||||
let dimension_usize = parse_index(&dimension, &span)?;
|
|
||||||
|
|
||||||
// Allocate the array dimension.
|
Ok(value)
|
||||||
let array = vec![value; dimension_usize];
|
|
||||||
|
|
||||||
// Set the array value.
|
|
||||||
value = ConstrainedValue::Array(array);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(value)
|
|
||||||
} else if expected_dimensions.first() == actual_dimensions.first() {
|
|
||||||
// Case 2 - enforce expression with updated array type.
|
|
||||||
let dimension = match expected_dimensions.remove_first() {
|
|
||||||
Some(number) => {
|
|
||||||
// Parse the array dimension into a `usize`.
|
|
||||||
parse_index(&number, &span)?
|
|
||||||
}
|
|
||||||
None => return Err(ExpressionError::unexpected_array(type_.to_string(), span)),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Update the actual array dimensions.
|
|
||||||
let _first_dimension = actual_dimensions.remove_first();
|
|
||||||
|
|
||||||
// Update the expected type to a new array type with the first dimension removed.
|
|
||||||
let expected_expression_type = Some(inner_array_type(*type_, expected_dimensions));
|
|
||||||
|
|
||||||
// If the expression has more dimensions.
|
|
||||||
let element_value = match actual_dimensions.first() {
|
|
||||||
Some(_dimension) => {
|
|
||||||
// Get the value of the array element as an initializer.
|
|
||||||
self.enforce_array_initializer(
|
|
||||||
cs,
|
|
||||||
file_scope,
|
|
||||||
function_scope,
|
|
||||||
expected_expression_type,
|
|
||||||
element_expression,
|
|
||||||
actual_dimensions.clone(),
|
|
||||||
span,
|
|
||||||
)?
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
// Get the value of the array element as an expression.
|
|
||||||
self.enforce_expression(
|
|
||||||
cs,
|
|
||||||
file_scope,
|
|
||||||
function_scope,
|
|
||||||
expected_expression_type,
|
|
||||||
element_expression,
|
|
||||||
)?
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Allocate the array of values.
|
|
||||||
let array_values = vec![element_value; dimension];
|
|
||||||
|
|
||||||
// Create a new value with the expected dimension.
|
|
||||||
Ok(ConstrainedValue::Array(array_values))
|
|
||||||
} else {
|
|
||||||
// Case 3 - return mismatched dimensions error.
|
|
||||||
Err(ExpressionError::invalid_first_dimension(
|
|
||||||
expected_dimensions
|
|
||||||
.first()
|
|
||||||
.ok_or_else(|| ExpressionError::undefined_first_dimension(span.clone()))?,
|
|
||||||
actual_dimensions
|
|
||||||
.first()
|
|
||||||
.ok_or_else(|| ExpressionError::undefined_first_dimension(span.clone()))?,
|
|
||||||
span,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// No explicit type given - evaluate array element expression.
|
|
||||||
let mut value =
|
|
||||||
self.enforce_expression(cs, file_scope, function_scope, expected_type, element_expression)?;
|
|
||||||
|
|
||||||
// Allocate the array.
|
|
||||||
while let Some(dimension) = actual_dimensions.remove_last() {
|
|
||||||
// Parse the dimension into a `usize`.
|
|
||||||
let dimension_usize = parse_index(&dimension, &span)?;
|
|
||||||
|
|
||||||
// Allocate the array dimension.
|
|
||||||
let array = vec![value; dimension_usize];
|
|
||||||
|
|
||||||
// Set the array value.
|
|
||||||
value = ConstrainedValue::Array(array);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Returns the index as a usize.
|
|
||||||
///
|
|
||||||
pub fn parse_index(number: &PositiveNumber, span: &Span) -> Result<usize, ExpressionError> {
|
|
||||||
number
|
|
||||||
.value
|
|
||||||
.parse::<usize>()
|
|
||||||
.map_err(|_| ExpressionError::invalid_index(number.value.to_owned(), span))
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Returns the type of the inner array given an array element and array dimensions.
|
|
||||||
///
|
|
||||||
/// If the array has no dimensions, then an inner array does not exist. Simply return the given
|
|
||||||
/// element type.
|
|
||||||
///
|
|
||||||
/// If the array has dimensions, then an inner array exists. Create a new type for the
|
|
||||||
/// inner array. The element type of the new array should be the same as the old array. The
|
|
||||||
/// dimensions of the new array should be the old array dimensions with the first dimension removed.
|
|
||||||
///
|
|
||||||
pub fn inner_array_type(element_type: Type, dimensions: ArrayDimensions) -> Type {
|
|
||||||
if dimensions.is_empty() {
|
|
||||||
// The array has one dimension.
|
|
||||||
element_type
|
|
||||||
} else {
|
|
||||||
// The array has multiple dimensions.
|
|
||||||
Type::Array(Box::new(element_type), dimensions)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,8 @@
|
|||||||
//! Enforces an array index expression in a compiled Leo program.
|
//! Enforces an array index expression in a compiled Leo program.
|
||||||
|
|
||||||
use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
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::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
@ -28,13 +29,10 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
pub(crate) fn enforce_index<CS: ConstraintSystem<F>>(
|
pub(crate) fn enforce_index<CS: ConstraintSystem<F>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: &str,
|
index: &Arc<Expression>,
|
||||||
function_scope: &str,
|
|
||||||
index: Expression,
|
|
||||||
span: &Span,
|
span: &Span,
|
||||||
) -> Result<usize, ExpressionError> {
|
) -> Result<usize, ExpressionError> {
|
||||||
let expected_type = Some(Type::IntegerType(IntegerType::U32));
|
match self.enforce_operand(cs, index)? {
|
||||||
match self.enforce_operand(cs, file_scope, function_scope, expected_type, index, &span)? {
|
|
||||||
ConstrainedValue::Integer(number) => Ok(number.to_usize(span)?),
|
ConstrainedValue::Integer(number) => Ok(number.to_usize(span)?),
|
||||||
value => Err(ExpressionError::invalid_index(value.to_string(), span)),
|
value => Err(ExpressionError::invalid_index(value.to_string(), span)),
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,8 @@
|
|||||||
//! Enforces a binary expression in a compiled Leo program.
|
//! Enforces a binary expression in a compiled Leo program.
|
||||||
|
|
||||||
use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
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::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
@ -31,19 +32,11 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
pub fn enforce_binary_expression<CS: ConstraintSystem<F>>(
|
pub fn enforce_binary_expression<CS: ConstraintSystem<F>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: &str,
|
left: &Arc<Expression>,
|
||||||
function_scope: &str,
|
right: &Arc<Expression>,
|
||||||
expected_type: Option<Type>,
|
|
||||||
left: Expression,
|
|
||||||
right: Expression,
|
|
||||||
span: &Span,
|
|
||||||
) -> Result<ConstrainedValuePair<F, G>, ExpressionError> {
|
) -> Result<ConstrainedValuePair<F, G>, ExpressionError> {
|
||||||
let mut resolved_left =
|
let resolved_left = self.enforce_operand(cs, left)?;
|
||||||
self.enforce_operand(cs, file_scope, function_scope, expected_type.clone(), left, span)?;
|
let resolved_right = self.enforce_operand(cs, right)?;
|
||||||
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)?;
|
|
||||||
|
|
||||||
Ok((resolved_left, resolved_right))
|
Ok((resolved_left, resolved_right))
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,8 @@
|
|||||||
//! Enforces one operand in a binary expression in a compiled Leo program.
|
//! Enforces one operand in a binary expression in a compiled Leo program.
|
||||||
|
|
||||||
use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
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::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
@ -31,16 +32,11 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
pub fn enforce_operand<CS: ConstraintSystem<F>>(
|
pub fn enforce_operand<CS: ConstraintSystem<F>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: &str,
|
expression: &Arc<Expression>,
|
||||||
function_scope: &str,
|
|
||||||
expected_type: Option<Type>,
|
|
||||||
expression: Expression,
|
|
||||||
span: &Span,
|
|
||||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||||
let mut branch = self.enforce_expression(cs, file_scope, function_scope, expected_type.clone(), expression)?;
|
let mut branch = self.enforce_expression(cs, expression)?;
|
||||||
|
|
||||||
branch.get_inner_mut();
|
branch.get_inner_mut();
|
||||||
branch.resolve_type(expected_type, span)?;
|
|
||||||
|
|
||||||
Ok(branch)
|
Ok(branch)
|
||||||
}
|
}
|
||||||
|
@ -16,82 +16,47 @@
|
|||||||
|
|
||||||
//! Enforces a circuit access expression in a compiled Leo program.
|
//! Enforces a circuit access expression in a compiled Leo program.
|
||||||
|
|
||||||
use crate::{
|
use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
||||||
errors::ExpressionError,
|
use leo_asg::{CircuitAccessExpression, Node};
|
||||||
program::{new_scope, ConstrainedProgram},
|
|
||||||
value::ConstrainedValue,
|
|
||||||
GroupType,
|
|
||||||
};
|
|
||||||
use leo_ast::{Expression, Identifier, Span, Type};
|
|
||||||
|
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
gadgets::r1cs::ConstraintSystem,
|
gadgets::r1cs::ConstraintSystem,
|
||||||
};
|
};
|
||||||
|
|
||||||
static SELF_KEYWORD: &str = "self";
|
|
||||||
|
|
||||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn enforce_circuit_access<CS: ConstraintSystem<F>>(
|
pub fn enforce_circuit_access<CS: ConstraintSystem<F>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: &str,
|
expr: &CircuitAccessExpression,
|
||||||
function_scope: &str,
|
|
||||||
expected_type: Option<Type>,
|
|
||||||
circuit_identifier: Expression,
|
|
||||||
circuit_member: Identifier,
|
|
||||||
span: Span,
|
|
||||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||||
// access a circuit member using the `self` keyword
|
if let Some(target) = &expr.target {
|
||||||
if let Expression::Identifier(ref identifier) = circuit_identifier {
|
//todo: we can prob pass values by ref here to avoid copying the entire circuit on access
|
||||||
if identifier.is_self() {
|
let target_value = self.enforce_operand(cs, target)?;
|
||||||
let self_file_scope = new_scope(&file_scope, &identifier.name);
|
match target_value {
|
||||||
let self_function_scope = new_scope(&self_file_scope, &identifier.name);
|
ConstrainedValue::CircuitExpression(def, members) => {
|
||||||
|
assert!(def.circuit == expr.circuit);
|
||||||
let member_value =
|
if let Some(member) = members.into_iter().find(|x| x.0.name == expr.member.name) {
|
||||||
self.evaluate_identifier(&self_file_scope, &self_function_scope, None, circuit_member)?;
|
Ok(member.1)
|
||||||
|
} else {
|
||||||
return Ok(member_value);
|
Err(ExpressionError::undefined_member_access(
|
||||||
}
|
expr.circuit.name.borrow().to_string(),
|
||||||
}
|
expr.member.to_string(),
|
||||||
|
expr.member.span.clone(),
|
||||||
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));
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
Ok(member.1)
|
value => Err(ExpressionError::undefined_circuit(
|
||||||
|
value.to_string(),
|
||||||
|
target.span().cloned().unwrap_or_default(),
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
None => Err(ExpressionError::undefined_member_access(
|
} else {
|
||||||
circuit_name.to_string(),
|
Err(ExpressionError::invalid_static_access(
|
||||||
circuit_member.to_string(),
|
expr.member.to_string(),
|
||||||
span,
|
expr.member.span.clone(),
|
||||||
)),
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,11 +18,11 @@
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::ExpressionError,
|
errors::ExpressionError,
|
||||||
program::{new_scope, ConstrainedProgram},
|
program::ConstrainedProgram,
|
||||||
value::{ConstrainedCircuitMember, ConstrainedValue},
|
value::{ConstrainedCircuitMember, ConstrainedValue},
|
||||||
GroupType,
|
GroupType,
|
||||||
};
|
};
|
||||||
use leo_ast::{CircuitMember, CircuitVariableDefinition, Identifier, Span};
|
use leo_asg::{CircuitInitExpression, CircuitMemberBody, Span};
|
||||||
|
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
@ -33,65 +33,34 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
pub fn enforce_circuit<CS: ConstraintSystem<F>>(
|
pub fn enforce_circuit<CS: ConstraintSystem<F>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: &str,
|
expr: &CircuitInitExpression,
|
||||||
function_scope: &str,
|
span: &Span,
|
||||||
identifier: Identifier,
|
|
||||||
members: Vec<CircuitVariableDefinition>,
|
|
||||||
span: Span,
|
|
||||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||||
// Circuit definitions are located at the minimum file scope
|
let circuit = expr
|
||||||
let minimum_scope = file_scope.split('_').next().unwrap();
|
.circuit
|
||||||
let identifier_string = identifier.to_string();
|
.body
|
||||||
let mut program_identifier = new_scope(minimum_scope, &identifier_string);
|
.borrow()
|
||||||
|
.upgrade()
|
||||||
|
.expect("circuit init stale circuit ref");
|
||||||
|
let members = circuit.members.borrow();
|
||||||
|
|
||||||
if identifier.is_self() {
|
let mut resolved_members = Vec::with_capacity(members.len());
|
||||||
program_identifier = file_scope.to_string();
|
|
||||||
|
// type checking is already done in asg
|
||||||
|
for (name, inner) in expr.values.iter() {
|
||||||
|
let target = members
|
||||||
|
.get(&name.name)
|
||||||
|
.expect("illegal name in asg circuit init expression");
|
||||||
|
match target {
|
||||||
|
CircuitMemberBody::Variable(_type_) => {
|
||||||
|
let variable_value = self.enforce_expression(cs, inner)?;
|
||||||
|
resolved_members.push(ConstrainedCircuitMember(name.clone(), variable_value));
|
||||||
|
}
|
||||||
|
_ => return Err(ExpressionError::expected_circuit_member(name.to_string(), span.clone())),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let circuit = match self.get(&program_identifier) {
|
let value = ConstrainedValue::CircuitExpression(circuit.clone(), resolved_members);
|
||||||
Some(value) => value.clone().extract_circuit(&span)?,
|
Ok(value)
|
||||||
None => return Err(ExpressionError::undefined_circuit(identifier.to_string(), span)),
|
|
||||||
};
|
|
||||||
|
|
||||||
let circuit_identifier = circuit.circuit_name.clone();
|
|
||||||
let mut resolved_members = Vec::with_capacity(circuit.members.len());
|
|
||||||
|
|
||||||
for member in circuit.members.into_iter() {
|
|
||||||
match member {
|
|
||||||
CircuitMember::CircuitVariable(identifier, type_) => {
|
|
||||||
let matched_variable = members
|
|
||||||
.clone()
|
|
||||||
.into_iter()
|
|
||||||
.find(|variable| variable.identifier.eq(&identifier));
|
|
||||||
match matched_variable {
|
|
||||||
Some(variable) => {
|
|
||||||
// Resolve and enforce circuit variable
|
|
||||||
let variable_value = self.enforce_expression(
|
|
||||||
cs,
|
|
||||||
file_scope,
|
|
||||||
function_scope,
|
|
||||||
Some(type_.clone()),
|
|
||||||
variable.expression,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
resolved_members.push(ConstrainedCircuitMember(identifier, variable_value))
|
|
||||||
}
|
|
||||||
None => return Err(ExpressionError::expected_circuit_member(identifier.to_string(), span)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CircuitMember::CircuitFunction(function) => {
|
|
||||||
let identifier = function.identifier.clone();
|
|
||||||
let constrained_function_value =
|
|
||||||
ConstrainedValue::Function(Some(circuit_identifier.clone()), Box::new(function));
|
|
||||||
|
|
||||||
resolved_members.push(ConstrainedCircuitMember(identifier, constrained_function_value));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(ConstrainedValue::CircuitExpression(
|
|
||||||
circuit_identifier,
|
|
||||||
resolved_members,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,3 @@ pub use self::access::*;
|
|||||||
|
|
||||||
pub mod circuit;
|
pub mod circuit;
|
||||||
pub use self::circuit::*;
|
pub use self::circuit::*;
|
||||||
|
|
||||||
pub mod static_access;
|
|
||||||
pub use self::static_access::*;
|
|
||||||
|
@ -1,80 +0,0 @@
|
|||||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
|
||||||
// This file is part of the Leo library.
|
|
||||||
|
|
||||||
// The Leo library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// The Leo library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
//! 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<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
|
||||||
pub fn enforce_circuit_static_access<CS: ConstraintSystem<F>>(
|
|
||||||
&mut self,
|
|
||||||
cs: &mut CS,
|
|
||||||
file_scope: &str,
|
|
||||||
function_scope: &str,
|
|
||||||
expected_type: Option<Type>,
|
|
||||||
circuit_identifier: Expression,
|
|
||||||
circuit_member: Identifier,
|
|
||||||
span: Span,
|
|
||||||
) -> Result<ConstrainedValue<F, G>, 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),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
@ -17,7 +17,8 @@
|
|||||||
//! Enforces a conditional expression in a compiled Leo program.
|
//! Enforces a conditional expression in a compiled Leo program.
|
||||||
|
|
||||||
use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
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::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
@ -30,23 +31,19 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
pub fn enforce_conditional_expression<CS: ConstraintSystem<F>>(
|
pub fn enforce_conditional_expression<CS: ConstraintSystem<F>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: &str,
|
conditional: &Arc<Expression>,
|
||||||
function_scope: &str,
|
first: &Arc<Expression>,
|
||||||
expected_type: Option<Type>,
|
second: &Arc<Expression>,
|
||||||
conditional: Expression,
|
|
||||||
first: Expression,
|
|
||||||
second: Expression,
|
|
||||||
span: &Span,
|
span: &Span,
|
||||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||||
let conditional_value =
|
let conditional_value = match self.enforce_expression(cs, conditional)? {
|
||||||
match self.enforce_expression(cs, file_scope, function_scope, Some(Type::Boolean), conditional)? {
|
ConstrainedValue::Boolean(resolved) => resolved,
|
||||||
ConstrainedValue::Boolean(resolved) => resolved,
|
value => return Err(ExpressionError::conditional_boolean(value.to_string(), span.to_owned())),
|
||||||
value => return Err(ExpressionError::conditional_boolean(value.to_string(), span.to_owned())),
|
};
|
||||||
};
|
|
||||||
|
|
||||||
let first_value = self.enforce_operand(cs, file_scope, function_scope, expected_type.clone(), first, span)?;
|
let first_value = self.enforce_operand(cs, first)?;
|
||||||
|
|
||||||
let second_value = self.enforce_operand(cs, file_scope, function_scope, expected_type, second, span)?;
|
let second_value = self.enforce_operand(cs, second)?;
|
||||||
|
|
||||||
let unique_namespace = cs.ns(|| {
|
let unique_namespace = cs.ns(|| {
|
||||||
format!(
|
format!(
|
||||||
|
@ -22,71 +22,49 @@ use crate::{
|
|||||||
logical::*,
|
logical::*,
|
||||||
program::ConstrainedProgram,
|
program::ConstrainedProgram,
|
||||||
relational::*,
|
relational::*,
|
||||||
value::{boolean::input::new_bool_constant, implicit::*, ConstrainedValue},
|
resolve_core_circuit,
|
||||||
Address,
|
value::{Address, ConstrainedValue, Integer},
|
||||||
FieldType,
|
FieldType,
|
||||||
GroupType,
|
GroupType,
|
||||||
Integer,
|
|
||||||
};
|
};
|
||||||
use leo_ast::{expression::*, Expression, Type};
|
use leo_asg::{expression::*, ConstValue, Expression, Node};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
gadgets::r1cs::ConstraintSystem,
|
gadgets::{r1cs::ConstraintSystem, utilities::boolean::Boolean},
|
||||||
};
|
};
|
||||||
|
|
||||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||||
pub(crate) fn enforce_expression<CS: ConstraintSystem<F>>(
|
pub(crate) fn enforce_expression<CS: ConstraintSystem<F>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: &str,
|
expression: &Arc<Expression>,
|
||||||
function_scope: &str,
|
|
||||||
expected_type: Option<Type>,
|
|
||||||
expression: Expression,
|
|
||||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||||
match expression {
|
let span = expression.span().cloned().unwrap_or_default();
|
||||||
|
match &**expression {
|
||||||
// Variables
|
// Variables
|
||||||
Expression::Identifier(unresolved_variable) => {
|
Expression::VariableRef(variable_ref) => self.evaluate_ref(variable_ref),
|
||||||
self.evaluate_identifier(file_scope, function_scope, expected_type, unresolved_variable)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Values
|
// Values
|
||||||
Expression::Value(ValueExpression::Address(address, span)) => {
|
Expression::Constant(Constant { value, .. }) => {
|
||||||
Ok(ConstrainedValue::Address(Address::constant(address, &span)?))
|
Ok(match value {
|
||||||
|
ConstValue::Address(value) => ConstrainedValue::Address(Address::constant(value.clone(), &span)?),
|
||||||
|
ConstValue::Boolean(value) => ConstrainedValue::Boolean(Boolean::Constant(*value)),
|
||||||
|
ConstValue::Field(value) => ConstrainedValue::Field(FieldType::constant(value.to_string(), &span)?),
|
||||||
|
ConstValue::Group(value) => ConstrainedValue::Group(G::constant(value, &span)?),
|
||||||
|
ConstValue::Int(value) => ConstrainedValue::Integer(Integer::new(value)),
|
||||||
|
ConstValue::Tuple(_) | ConstValue::Array(_) => unimplemented!(), // shouldnt be in the asg here
|
||||||
|
})
|
||||||
}
|
}
|
||||||
Expression::Value(ValueExpression::Boolean(boolean, span)) => {
|
|
||||||
Ok(ConstrainedValue::Boolean(new_bool_constant(boolean, &span)?))
|
|
||||||
}
|
|
||||||
Expression::Value(ValueExpression::Field(field, span)) => {
|
|
||||||
Ok(ConstrainedValue::Field(FieldType::constant(field, &span)?))
|
|
||||||
}
|
|
||||||
Expression::Value(ValueExpression::Group(group_element)) => {
|
|
||||||
Ok(ConstrainedValue::Group(G::constant(*group_element)?))
|
|
||||||
}
|
|
||||||
Expression::Value(ValueExpression::Implicit(value, span)) => {
|
|
||||||
Ok(enforce_number_implicit(expected_type, value, &span)?)
|
|
||||||
}
|
|
||||||
Expression::Value(ValueExpression::Integer(type_, integer, span)) => Ok(ConstrainedValue::Integer(
|
|
||||||
Integer::new(expected_type, &type_, integer, &span)?,
|
|
||||||
)),
|
|
||||||
|
|
||||||
// Binary operations
|
// Binary operations
|
||||||
Expression::Binary(BinaryExpression { left, right, op, span }) => {
|
Expression::Binary(BinaryExpression {
|
||||||
let (resolved_left, resolved_right) = self.enforce_binary_expression(
|
left, right, operation, ..
|
||||||
cs,
|
}) => {
|
||||||
file_scope,
|
let (resolved_left, resolved_right) = self.enforce_binary_expression(cs, left, right)?;
|
||||||
function_scope,
|
|
||||||
if op.class() == BinaryOperationClass::Numeric {
|
|
||||||
expected_type
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
},
|
|
||||||
*left,
|
|
||||||
*right,
|
|
||||||
&span,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
match op {
|
match operation {
|
||||||
BinaryOperation::Add => enforce_add(cs, resolved_left, resolved_right, &span),
|
BinaryOperation::Add => enforce_add(cs, resolved_left, resolved_right, &span),
|
||||||
BinaryOperation::Sub => enforce_sub(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),
|
BinaryOperation::Mul => enforce_mul(cs, resolved_left, resolved_right, &span),
|
||||||
@ -99,7 +77,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
enforce_and(cs, resolved_left, resolved_right, &span).map_err(ExpressionError::BooleanError)
|
enforce_and(cs, resolved_left, resolved_right, &span).map_err(ExpressionError::BooleanError)
|
||||||
}
|
}
|
||||||
BinaryOperation::Eq => evaluate_eq(cs, resolved_left, resolved_right, &span),
|
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),
|
.map_err(ExpressionError::BooleanError),
|
||||||
BinaryOperation::Ge => evaluate_ge(cs, resolved_left, resolved_right, &span),
|
BinaryOperation::Ge => evaluate_ge(cs, resolved_left, resolved_right, &span),
|
||||||
BinaryOperation::Gt => evaluate_gt(cs, resolved_left, resolved_right, &span),
|
BinaryOperation::Gt => evaluate_gt(cs, resolved_left, resolved_right, &span),
|
||||||
@ -109,114 +87,71 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Unary operations
|
// Unary operations
|
||||||
Expression::Unary(UnaryExpression { inner, op, span }) => match op {
|
Expression::Unary(UnaryExpression { inner, operation, .. }) => match operation {
|
||||||
UnaryOperation::Negate => {
|
UnaryOperation::Negate => {
|
||||||
let resolved_inner =
|
let resolved_inner = self.enforce_expression(cs, inner)?;
|
||||||
self.enforce_expression(cs, file_scope, function_scope, expected_type, *inner)?;
|
|
||||||
enforce_negate(cs, resolved_inner, &span)
|
enforce_negate(cs, resolved_inner, &span)
|
||||||
}
|
}
|
||||||
UnaryOperation::Not => Ok(evaluate_not(
|
UnaryOperation::Not => Ok(evaluate_not(self.enforce_operand(cs, inner)?, &span)?),
|
||||||
self.enforce_operand(cs, file_scope, function_scope, expected_type, *inner, &span)?,
|
|
||||||
span,
|
|
||||||
)?),
|
|
||||||
},
|
},
|
||||||
|
|
||||||
Expression::Ternary(TernaryExpression {
|
Expression::Ternary(TernaryExpression {
|
||||||
condition,
|
condition,
|
||||||
if_true,
|
if_true,
|
||||||
if_false,
|
if_false,
|
||||||
span,
|
..
|
||||||
}) => self.enforce_conditional_expression(
|
}) => self.enforce_conditional_expression(cs, condition, if_true, if_false, &span),
|
||||||
cs,
|
|
||||||
file_scope,
|
|
||||||
function_scope,
|
|
||||||
expected_type,
|
|
||||||
*condition,
|
|
||||||
*if_true,
|
|
||||||
*if_false,
|
|
||||||
&span,
|
|
||||||
),
|
|
||||||
|
|
||||||
// Arrays
|
// Arrays
|
||||||
Expression::ArrayInline(ArrayInlineExpression { elements, span }) => {
|
Expression::ArrayInline(ArrayInlineExpression { elements, .. }) => self.enforce_array(cs, elements, span),
|
||||||
self.enforce_array(cs, file_scope, function_scope, expected_type, elements, span)
|
Expression::ArrayInit(ArrayInitExpression { element, len, .. }) => {
|
||||||
|
self.enforce_array_initializer(cs, element, *len)
|
||||||
}
|
}
|
||||||
Expression::ArrayInit(ArrayInitExpression {
|
Expression::ArrayAccess(ArrayAccessExpression { array, index, .. }) => {
|
||||||
element,
|
self.enforce_array_access(cs, array, index, &span)
|
||||||
dimensions,
|
}
|
||||||
span,
|
Expression::ArrayRangeAccess(ArrayRangeAccessExpression { array, left, right, .. }) => {
|
||||||
}) => self.enforce_array_initializer(
|
self.enforce_array_range_access(cs, array, left.as_ref(), right.as_ref(), &span)
|
||||||
cs,
|
|
||||||
file_scope,
|
|
||||||
function_scope,
|
|
||||||
expected_type,
|
|
||||||
*element,
|
|
||||||
dimensions,
|
|
||||||
span,
|
|
||||||
),
|
|
||||||
Expression::ArrayAccess(ArrayAccessExpression { array, index, span }) => {
|
|
||||||
self.enforce_array_access(cs, file_scope, function_scope, expected_type, *array, *index, &span)
|
|
||||||
}
|
}
|
||||||
Expression::ArrayRangeAccess(ArrayRangeAccessExpression {
|
|
||||||
array,
|
|
||||||
left,
|
|
||||||
right,
|
|
||||||
span,
|
|
||||||
}) => self.enforce_array_range_access(
|
|
||||||
cs,
|
|
||||||
file_scope,
|
|
||||||
function_scope,
|
|
||||||
expected_type,
|
|
||||||
*array,
|
|
||||||
left.map(|x| *x),
|
|
||||||
right.map(|x| *x),
|
|
||||||
&span,
|
|
||||||
),
|
|
||||||
|
|
||||||
// Tuples
|
// Tuples
|
||||||
Expression::TupleInit(TupleInitExpression { elements, span }) => {
|
Expression::TupleInit(TupleInitExpression { elements, .. }) => self.enforce_tuple(cs, elements),
|
||||||
self.enforce_tuple(cs, file_scope, function_scope, expected_type, elements, span)
|
Expression::TupleAccess(TupleAccessExpression { tuple_ref, index, .. }) => {
|
||||||
}
|
self.enforce_tuple_access(cs, tuple_ref, *index, &span)
|
||||||
Expression::TupleAccess(TupleAccessExpression { tuple, index, span }) => {
|
|
||||||
self.enforce_tuple_access(cs, file_scope, function_scope, expected_type, *tuple, index, &span)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Circuits
|
// Circuits
|
||||||
Expression::CircuitInit(CircuitInitExpression { name, members, span }) => {
|
Expression::CircuitInit(expr) => self.enforce_circuit(cs, expr, &span),
|
||||||
self.enforce_circuit(cs, file_scope, function_scope, name, members, span)
|
Expression::CircuitAccess(expr) => self.enforce_circuit_access(cs, expr),
|
||||||
}
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
Expression::Call(CallExpression {
|
Expression::Call(CallExpression {
|
||||||
function,
|
function,
|
||||||
|
target,
|
||||||
arguments,
|
arguments,
|
||||||
span,
|
..
|
||||||
}) => match *function {
|
}) => {
|
||||||
Expression::Identifier(id) if id.is_core() => self.enforce_core_circuit_call_expression(
|
if let Some(circuit) = function
|
||||||
cs,
|
.circuit
|
||||||
file_scope,
|
.borrow()
|
||||||
function_scope,
|
.as_ref()
|
||||||
expected_type,
|
.map(|x| x.upgrade().expect("stale circuit for member function"))
|
||||||
id.name,
|
{
|
||||||
arguments,
|
let core_mapping = circuit.core_mapping.borrow();
|
||||||
span,
|
if let Some(core_mapping) = core_mapping.as_deref() {
|
||||||
),
|
let core_circuit = resolve_core_circuit::<F, G>(core_mapping);
|
||||||
function => self.enforce_function_call_expression(
|
return self.enforce_core_circuit_call_expression(
|
||||||
cs,
|
cs,
|
||||||
file_scope,
|
&core_circuit,
|
||||||
function_scope,
|
&function,
|
||||||
expected_type,
|
target.as_ref(),
|
||||||
function,
|
arguments,
|
||||||
arguments,
|
&span,
|
||||||
span,
|
);
|
||||||
),
|
}
|
||||||
},
|
}
|
||||||
|
self.enforce_function_call_expression(cs, &function, target.as_ref(), arguments, &span)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,61 +13,48 @@
|
|||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
use crate::{program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
use crate::{program::ConstrainedProgram, value::ConstrainedValue, CoreCircuit, GroupType};
|
||||||
|
|
||||||
use crate::errors::{ExpressionError, FunctionError};
|
use crate::errors::ExpressionError;
|
||||||
use leo_ast::{Expression, Span, Type};
|
use leo_asg::{Expression, Function, Span};
|
||||||
use leo_core::call_core_circuit;
|
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
gadgets::r1cs::ConstraintSystem,
|
gadgets::r1cs::ConstraintSystem,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||||
/// Call a default core circuit function with arguments
|
/// Call a default core circuit function with arguments
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn enforce_core_circuit_call_expression<CS: ConstraintSystem<F>>(
|
pub fn enforce_core_circuit_call_expression<CS: ConstraintSystem<F>, C: CoreCircuit<F, G>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: &str,
|
core_circuit: &C,
|
||||||
function_scope: &str,
|
function: &Arc<Function>,
|
||||||
expected_type: Option<Type>,
|
target: Option<&Arc<Expression>>,
|
||||||
core_circuit: String,
|
arguments: &[Arc<Expression>],
|
||||||
arguments: Vec<Expression>,
|
span: &Span,
|
||||||
span: Span,
|
|
||||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||||
// Get the value of each core function argument
|
let function = function
|
||||||
let mut argument_values = Vec::with_capacity(arguments.len());
|
.body
|
||||||
for argument in arguments.into_iter() {
|
.borrow()
|
||||||
let argument_value = self.enforce_expression(cs, file_scope, function_scope, None, argument)?;
|
.upgrade()
|
||||||
let core_function_argument = argument_value.to_value();
|
.expect("stale function in call expression");
|
||||||
|
|
||||||
argument_values.push(core_function_argument);
|
let target_value = if let Some(target) = target {
|
||||||
}
|
Some(self.enforce_expression(cs, target)?)
|
||||||
|
|
||||||
// Call the core function in `leo-core`
|
|
||||||
let res = call_core_circuit(cs, core_circuit, argument_values, span.clone())?;
|
|
||||||
|
|
||||||
// Convert the core function returns into constrained values
|
|
||||||
let returns = res.into_iter().map(ConstrainedValue::from).collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let return_value = if returns.len() == 1 {
|
|
||||||
// The function has a single return
|
|
||||||
returns[0].clone()
|
|
||||||
} else {
|
} else {
|
||||||
// The function has multiple returns
|
None
|
||||||
ConstrainedValue::Tuple(returns)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check that function returns expected type
|
// Get the value of each core function argument
|
||||||
if let Some(expected) = expected_type {
|
let arguments = arguments
|
||||||
let actual = return_value.to_type(&span)?;
|
.iter()
|
||||||
if expected.ne(&actual) {
|
.map(|argument| self.enforce_expression(cs, argument))
|
||||||
return Err(ExpressionError::FunctionError(Box::new(
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
FunctionError::return_argument_type(expected.to_string(), actual.to_string(), span),
|
|
||||||
)));
|
// Call the core function
|
||||||
}
|
let return_value = core_circuit.call_function(cs, function, span, target_value, arguments)?;
|
||||||
}
|
|
||||||
|
|
||||||
Ok(return_value)
|
Ok(return_value)
|
||||||
}
|
}
|
||||||
|
@ -16,8 +16,9 @@
|
|||||||
|
|
||||||
//! Enforce a function call expression in a compiled Leo program.
|
//! Enforce a function call expression in a compiled Leo program.
|
||||||
|
|
||||||
use crate::{errors::ExpressionError, new_scope, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
||||||
use leo_ast::{expression::CircuitMemberAccessExpression, Expression, Span, Type};
|
use leo_asg::{Expression, Function, Span};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
@ -29,51 +30,29 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
pub fn enforce_function_call_expression<CS: ConstraintSystem<F>>(
|
pub fn enforce_function_call_expression<CS: ConstraintSystem<F>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: &str,
|
function: &Arc<Function>,
|
||||||
function_scope: &str,
|
target: Option<&Arc<Expression>>,
|
||||||
expected_type: Option<Type>,
|
arguments: &[Arc<Expression>],
|
||||||
function: Expression,
|
span: &Span,
|
||||||
arguments: Vec<Expression>,
|
|
||||||
span: Span,
|
|
||||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
) -> Result<ConstrainedValue<F, G>, 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 = || {
|
let name_unique = || {
|
||||||
format!(
|
format!(
|
||||||
"function call {} {}:{}",
|
"function call {} {}:{}",
|
||||||
function_call.get_name(),
|
function.name.borrow().clone(),
|
||||||
span.line,
|
span.line,
|
||||||
span.start,
|
span.start,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
let function = function
|
||||||
|
.body
|
||||||
|
.borrow()
|
||||||
|
.upgrade()
|
||||||
|
.expect("stale function in call expression");
|
||||||
|
|
||||||
self.enforce_function(
|
let return_value = self
|
||||||
&mut cs.ns(name_unique),
|
.enforce_function(&mut cs.ns(name_unique), &function, target, arguments)
|
||||||
&outer_scope,
|
.map_err(|error| ExpressionError::from(Box::new(error)))?;
|
||||||
function_scope,
|
|
||||||
function_call,
|
Ok(return_value)
|
||||||
arguments,
|
|
||||||
&declared_circuit_reference,
|
|
||||||
)
|
|
||||||
.map_err(|error| ExpressionError::from(Box::new(error)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
|
||||||
// This file is part of the Leo library.
|
|
||||||
|
|
||||||
// The Leo library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// The Leo library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
//! Enforces an identifier expression in a compiled Leo program.
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
errors::ExpressionError,
|
|
||||||
program::{new_scope, ConstrainedProgram},
|
|
||||||
value::ConstrainedValue,
|
|
||||||
Address,
|
|
||||||
GroupType,
|
|
||||||
};
|
|
||||||
use leo_ast::{Identifier, Type};
|
|
||||||
|
|
||||||
use snarkvm_models::curves::{Field, PrimeField};
|
|
||||||
|
|
||||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|
||||||
/// Enforce a variable expression by getting the resolved value
|
|
||||||
pub fn evaluate_identifier(
|
|
||||||
&mut self,
|
|
||||||
file_scope: &str,
|
|
||||||
function_scope: &str,
|
|
||||||
expected_type: Option<Type>,
|
|
||||||
unresolved_identifier: Identifier,
|
|
||||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
|
||||||
// Evaluate the identifier name in the current function scope
|
|
||||||
let variable_name = new_scope(function_scope, &unresolved_identifier.name);
|
|
||||||
let identifier_name = new_scope(file_scope, &unresolved_identifier.name);
|
|
||||||
|
|
||||||
let mut result_value = if let Some(value) = self.get(&variable_name) {
|
|
||||||
// Reassigning variable to another variable
|
|
||||||
value.clone()
|
|
||||||
} else if let Some(value) = self.get(&identifier_name) {
|
|
||||||
// Check global scope (function and circuit names)
|
|
||||||
value.clone()
|
|
||||||
} else if let Some(value) = self.get(&unresolved_identifier.name) {
|
|
||||||
// Check imported file scope
|
|
||||||
value.clone()
|
|
||||||
} else if expected_type == Some(Type::Address) {
|
|
||||||
// If we expect an address type, try to return an address
|
|
||||||
let address = Address::constant(unresolved_identifier.name, &unresolved_identifier.span)?;
|
|
||||||
|
|
||||||
return Ok(ConstrainedValue::Address(address));
|
|
||||||
} else {
|
|
||||||
return Err(ExpressionError::undefined_identifier(unresolved_identifier));
|
|
||||||
};
|
|
||||||
|
|
||||||
result_value.resolve_type(expected_type, &unresolved_identifier.span)?;
|
|
||||||
|
|
||||||
Ok(result_value)
|
|
||||||
}
|
|
||||||
}
|
|
@ -17,7 +17,7 @@
|
|||||||
//! Enforces a logical `&&` operator in a resolved Leo program.
|
//! Enforces a logical `&&` operator in a resolved Leo program.
|
||||||
|
|
||||||
use crate::{errors::BooleanError, value::ConstrainedValue, GroupType};
|
use crate::{errors::BooleanError, value::ConstrainedValue, GroupType};
|
||||||
use leo_ast::Span;
|
use leo_asg::Span;
|
||||||
|
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
|
@ -17,16 +17,16 @@
|
|||||||
//! Enforces a logical `!` operator in a resolved Leo program.
|
//! Enforces a logical `!` operator in a resolved Leo program.
|
||||||
|
|
||||||
use crate::{errors::BooleanError, value::ConstrainedValue, GroupType};
|
use crate::{errors::BooleanError, value::ConstrainedValue, GroupType};
|
||||||
use leo_ast::Span;
|
use leo_asg::Span;
|
||||||
|
|
||||||
use snarkvm_models::curves::{Field, PrimeField};
|
use snarkvm_models::curves::{Field, PrimeField};
|
||||||
|
|
||||||
pub fn evaluate_not<F: Field + PrimeField, G: GroupType<F>>(
|
pub fn evaluate_not<F: Field + PrimeField, G: GroupType<F>>(
|
||||||
value: ConstrainedValue<F, G>,
|
value: ConstrainedValue<F, G>,
|
||||||
span: Span,
|
span: &Span,
|
||||||
) -> Result<ConstrainedValue<F, G>, BooleanError> {
|
) -> Result<ConstrainedValue<F, G>, BooleanError> {
|
||||||
match value {
|
match value {
|
||||||
ConstrainedValue::Boolean(boolean) => Ok(ConstrainedValue::Boolean(boolean.not())),
|
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())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
//! Enforces a logical `||` operator in a resolved Leo program.
|
//! Enforces a logical `||` operator in a resolved Leo program.
|
||||||
|
|
||||||
use crate::{errors::BooleanError, value::ConstrainedValue, GroupType};
|
use crate::{errors::BooleanError, value::ConstrainedValue, GroupType};
|
||||||
use leo_ast::Span;
|
use leo_asg::Span;
|
||||||
|
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
|
@ -37,8 +37,8 @@ pub use self::expression::*;
|
|||||||
pub mod function;
|
pub mod function;
|
||||||
pub use self::function::*;
|
pub use self::function::*;
|
||||||
|
|
||||||
pub mod identifier;
|
pub mod variable_ref;
|
||||||
pub use self::identifier::*;
|
pub use self::variable_ref::*;
|
||||||
|
|
||||||
pub mod logical;
|
pub mod logical;
|
||||||
pub use self::logical::*;
|
pub use self::logical::*;
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
//! Enforces a relational `==` operator in a resolved Leo program.
|
//! Enforces a relational `==` operator in a resolved Leo program.
|
||||||
|
|
||||||
use crate::{enforce_and, errors::ExpressionError, value::ConstrainedValue, GroupType};
|
use crate::{enforce_and, errors::ExpressionError, value::ConstrainedValue, GroupType};
|
||||||
use leo_ast::Span;
|
use leo_asg::Span;
|
||||||
|
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
@ -74,16 +74,6 @@ pub fn evaluate_eq<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<
|
|||||||
}
|
}
|
||||||
return Ok(current);
|
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) => {
|
(val_1, val_2) => {
|
||||||
return Err(ExpressionError::incompatible_types(
|
return Err(ExpressionError::incompatible_types(
|
||||||
format!("{} == {}", val_1, val_2,),
|
format!("{} == {}", val_1, val_2,),
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
//! Enforces a relational `>=` operator in a resolved Leo program.
|
//! Enforces a relational `>=` operator in a resolved Leo program.
|
||||||
|
|
||||||
use crate::{errors::ExpressionError, value::ConstrainedValue, GroupType};
|
use crate::{errors::ExpressionError, value::ConstrainedValue, GroupType};
|
||||||
use leo_ast::Span;
|
use leo_asg::Span;
|
||||||
use leo_gadgets::bits::ComparatorGadget;
|
use leo_gadgets::bits::ComparatorGadget;
|
||||||
|
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
@ -31,19 +31,11 @@ pub fn evaluate_ge<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<
|
|||||||
right: ConstrainedValue<F, G>,
|
right: ConstrainedValue<F, G>,
|
||||||
span: &Span,
|
span: &Span,
|
||||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||||
let mut unique_namespace = cs.ns(|| format!("evaluate {} >= {} {}:{}", left, right, span.line, span.start));
|
let unique_namespace = cs.ns(|| format!("evaluate {} >= {} {}:{}", left, right, span.line, span.start));
|
||||||
let constraint_result = match (left, right) {
|
let constraint_result = match (left, right) {
|
||||||
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
||||||
num_1.greater_than_or_equal(unique_namespace, &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) => {
|
(val_1, val_2) => {
|
||||||
return Err(ExpressionError::incompatible_types(
|
return Err(ExpressionError::incompatible_types(
|
||||||
format!("{} >= {}", val_1, val_2),
|
format!("{} >= {}", val_1, val_2),
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
//! Enforces a relational `>` operator in a resolved Leo program.
|
//! Enforces a relational `>` operator in a resolved Leo program.
|
||||||
|
|
||||||
use crate::{errors::ExpressionError, value::ConstrainedValue, GroupType};
|
use crate::{errors::ExpressionError, value::ConstrainedValue, GroupType};
|
||||||
use leo_ast::Span;
|
use leo_asg::Span;
|
||||||
use leo_gadgets::bits::ComparatorGadget;
|
use leo_gadgets::bits::ComparatorGadget;
|
||||||
|
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
@ -31,19 +31,11 @@ pub fn evaluate_gt<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<
|
|||||||
right: ConstrainedValue<F, G>,
|
right: ConstrainedValue<F, G>,
|
||||||
span: &Span,
|
span: &Span,
|
||||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||||
let mut unique_namespace = cs.ns(|| format!("evaluate {} > {} {}:{}", left, right, span.line, span.start));
|
let unique_namespace = cs.ns(|| format!("evaluate {} > {} {}:{}", left, right, span.line, span.start));
|
||||||
let constraint_result = match (left, right) {
|
let constraint_result = match (left, right) {
|
||||||
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
||||||
num_1.greater_than(unique_namespace, &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) => {
|
(val_1, val_2) => {
|
||||||
return Err(ExpressionError::incompatible_types(
|
return Err(ExpressionError::incompatible_types(
|
||||||
format!("{} > {}", val_1, val_2),
|
format!("{} > {}", val_1, val_2),
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
//! Enforces a relational `<=` operator in a resolved Leo program.
|
//! Enforces a relational `<=` operator in a resolved Leo program.
|
||||||
|
|
||||||
use crate::{errors::ExpressionError, value::ConstrainedValue, GroupType};
|
use crate::{errors::ExpressionError, value::ConstrainedValue, GroupType};
|
||||||
use leo_ast::Span;
|
use leo_asg::Span;
|
||||||
use leo_gadgets::bits::ComparatorGadget;
|
use leo_gadgets::bits::ComparatorGadget;
|
||||||
|
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
@ -31,19 +31,11 @@ pub fn evaluate_le<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<
|
|||||||
right: ConstrainedValue<F, G>,
|
right: ConstrainedValue<F, G>,
|
||||||
span: &Span,
|
span: &Span,
|
||||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||||
let mut unique_namespace = cs.ns(|| format!("evaluate {} <= {} {}:{}", left, right, span.line, span.start));
|
let unique_namespace = cs.ns(|| format!("evaluate {} <= {} {}:{}", left, right, span.line, span.start));
|
||||||
let constraint_result = match (left, right) {
|
let constraint_result = match (left, right) {
|
||||||
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
||||||
num_1.less_than_or_equal(unique_namespace, &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) => {
|
(val_1, val_2) => {
|
||||||
return Err(ExpressionError::incompatible_types(
|
return Err(ExpressionError::incompatible_types(
|
||||||
format!("{} <= {}", val_1, val_2),
|
format!("{} <= {}", val_1, val_2),
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
//! Enforces a relational `<` operator in a resolved Leo program.
|
//! Enforces a relational `<` operator in a resolved Leo program.
|
||||||
|
|
||||||
use crate::{errors::ExpressionError, value::ConstrainedValue, GroupType};
|
use crate::{errors::ExpressionError, value::ConstrainedValue, GroupType};
|
||||||
use leo_ast::Span;
|
use leo_asg::Span;
|
||||||
use leo_gadgets::bits::comparator::EvaluateLtGadget;
|
use leo_gadgets::bits::comparator::EvaluateLtGadget;
|
||||||
|
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
@ -31,19 +31,11 @@ pub fn evaluate_lt<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<
|
|||||||
right: ConstrainedValue<F, G>,
|
right: ConstrainedValue<F, G>,
|
||||||
span: &Span,
|
span: &Span,
|
||||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||||
let mut unique_namespace = cs.ns(|| format!("evaluate {} < {} {}:{}", left, right, span.line, span.start));
|
let unique_namespace = cs.ns(|| format!("evaluate {} < {} {}:{}", left, right, span.line, span.start));
|
||||||
let constraint_result = match (left, right) {
|
let constraint_result = match (left, right) {
|
||||||
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
||||||
num_1.less_than(unique_namespace, &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) => {
|
(val_1, val_2) => {
|
||||||
return Err(ExpressionError::incompatible_types(
|
return Err(ExpressionError::incompatible_types(
|
||||||
format!("{} < {}", val_1, val_2),
|
format!("{} < {}", val_1, val_2),
|
||||||
|
@ -16,8 +16,9 @@
|
|||||||
|
|
||||||
//! Enforces array access in a compiled Leo program.
|
//! Enforces array access in a compiled Leo program.
|
||||||
|
|
||||||
use crate::{errors::ExpressionError, parse_index, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
||||||
use leo_ast::{Expression, PositiveNumber, Span, Type};
|
use leo_asg::{Expression, Span};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
@ -29,27 +30,22 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
pub fn enforce_tuple_access<CS: ConstraintSystem<F>>(
|
pub fn enforce_tuple_access<CS: ConstraintSystem<F>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: &str,
|
tuple: &Arc<Expression>,
|
||||||
function_scope: &str,
|
index: usize,
|
||||||
expected_type: Option<Type>,
|
|
||||||
tuple: Expression,
|
|
||||||
index: PositiveNumber,
|
|
||||||
span: &Span,
|
span: &Span,
|
||||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||||
// Get the tuple values.
|
// Get the tuple values.
|
||||||
let tuple = match self.enforce_operand(cs, file_scope, function_scope, expected_type, tuple, &span)? {
|
let tuple = match self.enforce_operand(cs, tuple)? {
|
||||||
ConstrainedValue::Tuple(tuple) => tuple,
|
ConstrainedValue::Tuple(tuple) => tuple,
|
||||||
value => return Err(ExpressionError::undefined_array(value.to_string(), span.to_owned())),
|
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.
|
// Check for out of bounds access.
|
||||||
if index_usize > tuple.len() - 1 {
|
if index > tuple.len() - 1 {
|
||||||
return Err(ExpressionError::index_out_of_bounds(index_usize, span.to_owned()));
|
// 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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,8 @@
|
|||||||
//! Enforces an tuple expression in a compiled Leo program.
|
//! Enforces an tuple expression in a compiled Leo program.
|
||||||
|
|
||||||
use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
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::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
@ -29,38 +30,11 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
pub fn enforce_tuple<CS: ConstraintSystem<F>>(
|
pub fn enforce_tuple<CS: ConstraintSystem<F>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: &str,
|
tuple: &[Arc<Expression>],
|
||||||
function_scope: &str,
|
|
||||||
expected_type: Option<Type>,
|
|
||||||
tuple: Vec<Expression>,
|
|
||||||
span: Span,
|
|
||||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
) -> Result<ConstrainedValue<F, G>, 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());
|
let mut result = Vec::with_capacity(tuple.len());
|
||||||
for (i, expression) in tuple.into_iter().enumerate() {
|
for expression in tuple.iter() {
|
||||||
let type_ = if expected_types.is_empty() {
|
result.push(self.enforce_expression(cs, expression)?);
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(expected_types[i].clone())
|
|
||||||
};
|
|
||||||
|
|
||||||
result.push(self.enforce_expression(cs, file_scope, function_scope, type_, expression)?);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ConstrainedValue::Tuple(result))
|
Ok(ConstrainedValue::Tuple(result))
|
||||||
|
@ -16,5 +16,5 @@
|
|||||||
|
|
||||||
//! Methods to enforce identifier expressions in a compiled Leo program.
|
//! Methods to enforce identifier expressions in a compiled Leo program.
|
||||||
|
|
||||||
pub mod identifier;
|
pub mod variable_ref;
|
||||||
pub use self::identifier::*;
|
pub use self::variable_ref::*;
|
@ -14,27 +14,24 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{new_scope, ConstrainedProgram, ConstrainedValue, GroupType};
|
//! Enforces an identifier expression in a compiled Leo program.
|
||||||
use leo_ast::Package;
|
|
||||||
|
use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
||||||
|
use leo_asg::VariableRef;
|
||||||
|
|
||||||
use leo_core::{CorePackageList, LeoCorePackageError};
|
|
||||||
use snarkvm_models::curves::{Field, PrimeField};
|
use snarkvm_models::curves::{Field, PrimeField};
|
||||||
|
|
||||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||||
pub(crate) fn store_core_package(&mut self, scope: &str, package: Package) -> Result<(), LeoCorePackageError> {
|
/// Enforce a variable expression by getting the resolved value
|
||||||
// Create list of imported core packages.
|
pub fn evaluate_ref(&mut self, variable_ref: &VariableRef) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||||
let list = CorePackageList::from_package_access(package.access)?;
|
// Evaluate the identifier name in the current function scope
|
||||||
|
let variable = variable_ref.variable.borrow();
|
||||||
|
let result_value = if let Some(value) = self.get(&variable.id) {
|
||||||
|
value.clone()
|
||||||
|
} else {
|
||||||
|
return Err(ExpressionError::undefined_identifier(variable.name.clone())); // todo: probably can be a panic here instead
|
||||||
|
};
|
||||||
|
|
||||||
// Fetch core packages from `leo-core`.
|
Ok(result_value)
|
||||||
let symbol_list = list.to_symbols()?;
|
|
||||||
|
|
||||||
for (symbol, circuit) in symbol_list.symbols() {
|
|
||||||
let symbol_name = new_scope(scope, symbol);
|
|
||||||
|
|
||||||
// store packages
|
|
||||||
self.store(symbol_name, ConstrainedValue::CircuitDefinition(circuit.to_owned()))
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -16,14 +16,10 @@
|
|||||||
|
|
||||||
//! Enforces constraints on a function in a compiled Leo program.
|
//! Enforces constraints on a function in a compiled Leo program.
|
||||||
|
|
||||||
use crate::{
|
use crate::{errors::FunctionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
||||||
errors::FunctionError,
|
|
||||||
program::{new_scope, ConstrainedProgram},
|
|
||||||
value::ConstrainedValue,
|
|
||||||
GroupType,
|
|
||||||
};
|
|
||||||
|
|
||||||
use leo_ast::{Expression, Function, FunctionInput};
|
use leo_asg::{Expression, FunctionBody, FunctionQualifier};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
@ -34,83 +30,77 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
pub(crate) fn enforce_function<CS: ConstraintSystem<F>>(
|
pub(crate) fn enforce_function<CS: ConstraintSystem<F>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
scope: &str,
|
function: &Arc<FunctionBody>,
|
||||||
caller_scope: &str,
|
target: Option<&Arc<Expression>>,
|
||||||
function: Function,
|
arguments: &[Arc<Expression>],
|
||||||
input: Vec<Expression>,
|
|
||||||
declared_circuit_reference: &str,
|
|
||||||
) -> Result<ConstrainedValue<F, G>, FunctionError> {
|
) -> Result<ConstrainedValue<F, G>, FunctionError> {
|
||||||
let function_name = new_scope(scope, function.get_name());
|
let target_value = if let Some(target) = target {
|
||||||
|
Some(self.enforce_expression(cs, target)?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
// Store if function contains input `mut self`.
|
let self_var = if let Some(target) = &target_value {
|
||||||
let mut_self = function.contains_mut_self();
|
let self_var = function
|
||||||
|
.scope
|
||||||
|
.borrow()
|
||||||
|
.resolve_variable("self")
|
||||||
|
.expect("attempted to call static function from non-static context");
|
||||||
|
self.store(self_var.borrow().id, target.clone());
|
||||||
|
Some(self_var)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
if function.arguments.len() != arguments.len() {
|
||||||
|
return Err(FunctionError::input_not_found(
|
||||||
|
"arguments length invalid".to_string(),
|
||||||
|
function.span.clone().unwrap_or_default(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
// Store input values as new variables in resolved program
|
// Store input values as new variables in resolved program
|
||||||
for (input_model, input_expression) in function.filter_self_inputs().zip(input.into_iter()) {
|
for (variable, input_expression) in function.arguments.iter().zip(arguments.iter()) {
|
||||||
let (name, value) = match input_model {
|
let mut input_value = self.enforce_expression(cs, input_expression)?;
|
||||||
FunctionInput::InputKeyword(keyword) => {
|
let variable = variable.borrow();
|
||||||
let value =
|
|
||||||
self.enforce_function_input(cs, scope, caller_scope, &function_name, None, input_expression)?;
|
|
||||||
|
|
||||||
(keyword.to_string(), value)
|
if variable.mutable {
|
||||||
}
|
input_value = ConstrainedValue::Mutable(Box::new(input_value))
|
||||||
FunctionInput::SelfKeyword(keyword) => {
|
}
|
||||||
let value =
|
|
||||||
self.enforce_function_input(cs, scope, caller_scope, &function_name, None, input_expression)?;
|
|
||||||
|
|
||||||
(keyword.to_string(), value)
|
self.store(variable.id, input_value);
|
||||||
}
|
|
||||||
FunctionInput::MutSelfKeyword(keyword) => {
|
|
||||||
let value =
|
|
||||||
self.enforce_function_input(cs, scope, caller_scope, &function_name, None, input_expression)?;
|
|
||||||
|
|
||||||
(keyword.to_string(), value)
|
|
||||||
}
|
|
||||||
FunctionInput::Variable(input_model) => {
|
|
||||||
// First evaluate input expression
|
|
||||||
let mut input_value = self.enforce_function_input(
|
|
||||||
cs,
|
|
||||||
scope,
|
|
||||||
caller_scope,
|
|
||||||
&function_name,
|
|
||||||
Some(input_model.type_.clone()),
|
|
||||||
input_expression,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
if input_model.mutable {
|
|
||||||
input_value = ConstrainedValue::Mutable(Box::new(input_value))
|
|
||||||
}
|
|
||||||
|
|
||||||
(input_model.identifier.name.clone(), input_value)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Store input as variable with {function_name}_{input_name}
|
|
||||||
let input_program_identifier = new_scope(&function_name, &name);
|
|
||||||
self.store(input_program_identifier, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Evaluate every statement in the function and save all potential results
|
// Evaluate every statement in the function and save all potential results
|
||||||
let mut results = vec![];
|
let mut results = vec![];
|
||||||
let indicator = Boolean::constant(true);
|
let indicator = Boolean::constant(true);
|
||||||
|
|
||||||
for statement in function.block.statements.iter() {
|
let output = function.function.output.clone().strong();
|
||||||
let mut result = self.enforce_statement(
|
|
||||||
cs,
|
|
||||||
scope,
|
|
||||||
&function_name,
|
|
||||||
&indicator,
|
|
||||||
statement.clone(),
|
|
||||||
function.output.clone(),
|
|
||||||
declared_circuit_reference,
|
|
||||||
mut_self,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
results.append(&mut result);
|
let mut result = self.enforce_statement(cs, &indicator, &function.body)?;
|
||||||
|
|
||||||
|
results.append(&mut result);
|
||||||
|
|
||||||
|
if function.function.qualifier == FunctionQualifier::MutSelfRef {
|
||||||
|
if let (Some(self_var), Some(target)) = (self_var, target) {
|
||||||
|
let new_self = self
|
||||||
|
.get(&self_var.borrow().id)
|
||||||
|
.expect("no self variable found in mut self context")
|
||||||
|
.clone();
|
||||||
|
if let Some(assignable_target) = self.resolve_mut_ref(cs, target)? {
|
||||||
|
if assignable_target.len() != 1 {
|
||||||
|
panic!("found tuple as a self assignment target");
|
||||||
|
}
|
||||||
|
let assignable_target = assignable_target.into_iter().next().unwrap();
|
||||||
|
*assignable_target = new_self;
|
||||||
|
} else {
|
||||||
|
// todo: we should report a warning for calling a mutable function on an effectively copied self (i.e. wasn't assignable `tempStruct {x: 5}.myMutSelfFunction()`)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Conditionally select a result based on returned indicators
|
// Conditionally select a result based on returned indicators
|
||||||
Self::conditionally_select_result(cs, function.output, results, &function.span)
|
Self::conditionally_select_result(cs, &output, results, &function.span.clone().unwrap_or_default())
|
||||||
.map_err(FunctionError::StatementError)
|
.map_err(FunctionError::StatementError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,18 +16,11 @@
|
|||||||
|
|
||||||
//! Allocates an array as a main function input parameter in a compiled Leo program.
|
//! Allocates an array as a main function input parameter in a compiled Leo program.
|
||||||
|
|
||||||
use crate::{
|
use crate::{errors::FunctionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
||||||
errors::FunctionError,
|
|
||||||
inner_array_type,
|
|
||||||
parse_index,
|
|
||||||
program::{new_scope, ConstrainedProgram},
|
|
||||||
value::ConstrainedValue,
|
|
||||||
GroupType,
|
|
||||||
};
|
|
||||||
|
|
||||||
use leo_ast::{ArrayDimensions, InputValue, Span, Type};
|
use leo_asg::Type;
|
||||||
|
use leo_ast::{InputValue, Span};
|
||||||
|
|
||||||
use crate::errors::ExpressionError;
|
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
gadgets::r1cs::ConstraintSystem,
|
gadgets::r1cs::ConstraintSystem,
|
||||||
@ -38,27 +31,11 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
name: &str,
|
name: &str,
|
||||||
array_type: Type,
|
array_type: &Type,
|
||||||
mut array_dimensions: ArrayDimensions,
|
array_len: usize,
|
||||||
input_value: Option<InputValue>,
|
input_value: Option<InputValue>,
|
||||||
span: &Span,
|
span: &Span,
|
||||||
) -> Result<ConstrainedValue<F, G>, FunctionError> {
|
) -> Result<ConstrainedValue<F, G>, FunctionError> {
|
||||||
let expected_length = match array_dimensions.remove_first() {
|
|
||||||
Some(number) => {
|
|
||||||
// Parse the array dimension into a `usize`.
|
|
||||||
parse_index(&number, &span)?
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
return Err(FunctionError::ExpressionError(ExpressionError::unexpected_array(
|
|
||||||
array_type.to_string(),
|
|
||||||
span.to_owned(),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get the expected type for each array element.
|
|
||||||
let inner_array_type = inner_array_type(array_type, array_dimensions);
|
|
||||||
|
|
||||||
// Build the array value using the expected types.
|
// Build the array value using the expected types.
|
||||||
let mut array_value = vec![];
|
let mut array_value = vec![];
|
||||||
|
|
||||||
@ -66,11 +43,11 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
Some(InputValue::Array(arr)) => {
|
Some(InputValue::Array(arr)) => {
|
||||||
// Allocate each value in the current row
|
// Allocate each value in the current row
|
||||||
for (i, value) in arr.into_iter().enumerate() {
|
for (i, value) in arr.into_iter().enumerate() {
|
||||||
let value_name = new_scope(&name, &i.to_string());
|
let value_name = format!("{}_{}", &name, &i.to_string());
|
||||||
|
|
||||||
array_value.push(self.allocate_main_function_input(
|
array_value.push(self.allocate_main_function_input(
|
||||||
cs,
|
cs,
|
||||||
inner_array_type.clone(),
|
array_type,
|
||||||
&value_name,
|
&value_name,
|
||||||
Some(value),
|
Some(value),
|
||||||
span,
|
span,
|
||||||
@ -79,16 +56,10 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
// Allocate all row values as none
|
// Allocate all row values as none
|
||||||
for i in 0..expected_length {
|
for i in 0..array_len {
|
||||||
let value_name = new_scope(&name, &i.to_string());
|
let value_name = format!("{}_{}", &name, &i.to_string());
|
||||||
|
|
||||||
array_value.push(self.allocate_main_function_input(
|
array_value.push(self.allocate_main_function_input(cs, array_type, &value_name, None, span)?);
|
||||||
cs,
|
|
||||||
inner_array_type.clone(),
|
|
||||||
&value_name,
|
|
||||||
None,
|
|
||||||
span,
|
|
||||||
)?);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
|
||||||
// This file is part of the Leo library.
|
|
||||||
|
|
||||||
// The Leo library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// The Leo library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
//! Enforces a function input parameter in a compiled Leo program.
|
|
||||||
|
|
||||||
use crate::{errors::FunctionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
|
||||||
|
|
||||||
use leo_ast::{Expression, Type};
|
|
||||||
|
|
||||||
use snarkvm_models::{
|
|
||||||
curves::{Field, PrimeField},
|
|
||||||
gadgets::r1cs::ConstraintSystem,
|
|
||||||
};
|
|
||||||
|
|
||||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|
||||||
pub fn enforce_function_input<CS: ConstraintSystem<F>>(
|
|
||||||
&mut self,
|
|
||||||
cs: &mut CS,
|
|
||||||
scope: &str,
|
|
||||||
caller_scope: &str,
|
|
||||||
function_name: &str,
|
|
||||||
expected_type: Option<Type>,
|
|
||||||
input: Expression,
|
|
||||||
) -> Result<ConstrainedValue<F, G>, FunctionError> {
|
|
||||||
// Evaluate the function input value as pass by value from the caller or
|
|
||||||
// evaluate as an expression in the current function scope
|
|
||||||
match input {
|
|
||||||
Expression::Identifier(identifier) => {
|
|
||||||
Ok(self.evaluate_identifier(caller_scope, function_name, expected_type, identifier)?)
|
|
||||||
}
|
|
||||||
expression => Ok(self.enforce_expression(cs, scope, function_name, expected_type, expression)?),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -15,7 +15,9 @@
|
|||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{errors::FunctionError, ConstrainedCircuitMember, ConstrainedProgram, ConstrainedValue, GroupType};
|
use crate::{errors::FunctionError, ConstrainedCircuitMember, ConstrainedProgram, ConstrainedValue, GroupType};
|
||||||
use leo_ast::{Identifier, Input, InputKeyword};
|
use leo_asg::{CircuitBody, CircuitMemberBody, Type};
|
||||||
|
use leo_ast::{Identifier, Input, Span};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
@ -31,26 +33,27 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
pub fn allocate_input_keyword<CS: ConstraintSystem<F>>(
|
pub fn allocate_input_keyword<CS: ConstraintSystem<F>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
keyword: InputKeyword,
|
span: Span,
|
||||||
|
expected_type: &Arc<CircuitBody>,
|
||||||
input: &Input,
|
input: &Input,
|
||||||
) -> Result<ConstrainedValue<F, G>, FunctionError> {
|
) -> Result<ConstrainedValue<F, G>, FunctionError> {
|
||||||
// Create an identifier for each input variable
|
// Create an identifier for each input variable
|
||||||
|
|
||||||
let registers_name = Identifier {
|
let registers_name = Identifier {
|
||||||
name: REGISTERS_VARIABLE_NAME.to_string(),
|
name: REGISTERS_VARIABLE_NAME.to_string(),
|
||||||
span: keyword.span.clone(),
|
span: span.clone(),
|
||||||
};
|
};
|
||||||
let record_name = Identifier {
|
let record_name = Identifier {
|
||||||
name: RECORD_VARIABLE_NAME.to_string(),
|
name: RECORD_VARIABLE_NAME.to_string(),
|
||||||
span: keyword.span.clone(),
|
span: span.clone(),
|
||||||
};
|
};
|
||||||
let state_name = Identifier {
|
let state_name = Identifier {
|
||||||
name: STATE_VARIABLE_NAME.to_string(),
|
name: STATE_VARIABLE_NAME.to_string(),
|
||||||
span: keyword.span.clone(),
|
span: span.clone(),
|
||||||
};
|
};
|
||||||
let state_leaf_name = Identifier {
|
let state_leaf_name = Identifier {
|
||||||
name: STATE_LEAF_VARIABLE_NAME.to_string(),
|
name: STATE_LEAF_VARIABLE_NAME.to_string(),
|
||||||
span: keyword.span.clone(),
|
span,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fetch each input variable's definitions
|
// Fetch each input variable's definitions
|
||||||
@ -72,8 +75,17 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
let mut members = Vec::with_capacity(sections.len());
|
let mut members = Vec::with_capacity(sections.len());
|
||||||
|
|
||||||
for (name, values) in sections {
|
for (name, values) in sections {
|
||||||
|
let sub_circuit = match expected_type.members.borrow().get(&name.name) {
|
||||||
|
Some(CircuitMemberBody::Variable(Type::Circuit(circuit))) => circuit
|
||||||
|
.body
|
||||||
|
.borrow()
|
||||||
|
.upgrade()
|
||||||
|
.expect("stale circuit body for input subtype"),
|
||||||
|
_ => panic!("illegal input type definition from asg"),
|
||||||
|
};
|
||||||
|
|
||||||
let member_name = name.clone();
|
let member_name = name.clone();
|
||||||
let member_value = self.allocate_input_section(cs, name, values)?;
|
let member_value = self.allocate_input_section(cs, name, sub_circuit, values)?;
|
||||||
|
|
||||||
let member = ConstrainedCircuitMember(member_name, member_value);
|
let member = ConstrainedCircuitMember(member_name, member_value);
|
||||||
|
|
||||||
@ -82,6 +94,6 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
|
|
||||||
// Return input variable keyword as circuit expression
|
// Return input variable keyword as circuit expression
|
||||||
|
|
||||||
Ok(ConstrainedValue::CircuitExpression(Identifier::from(keyword), members))
|
Ok(ConstrainedValue::CircuitExpression(expected_type.clone(), members))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,9 @@
|
|||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{errors::FunctionError, ConstrainedCircuitMember, ConstrainedProgram, ConstrainedValue, GroupType};
|
use crate::{errors::FunctionError, ConstrainedCircuitMember, ConstrainedProgram, ConstrainedValue, GroupType};
|
||||||
|
use leo_asg::{AsgConvertError, CircuitBody, CircuitMemberBody};
|
||||||
use leo_ast::{Identifier, InputValue, Parameter};
|
use leo_ast::{Identifier, InputValue, Parameter};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
@ -29,6 +31,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
identifier: Identifier,
|
identifier: Identifier,
|
||||||
|
expected_type: Arc<CircuitBody>,
|
||||||
section: IndexMap<Parameter, Option<InputValue>>,
|
section: IndexMap<Parameter, Option<InputValue>>,
|
||||||
) -> Result<ConstrainedValue<F, G>, FunctionError> {
|
) -> Result<ConstrainedValue<F, G>, FunctionError> {
|
||||||
let mut members = Vec::with_capacity(section.len());
|
let mut members = Vec::with_capacity(section.len());
|
||||||
@ -36,10 +39,24 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
// Allocate each section definition as a circuit member value
|
// Allocate each section definition as a circuit member value
|
||||||
|
|
||||||
for (parameter, option) in section.into_iter() {
|
for (parameter, option) in section.into_iter() {
|
||||||
|
let section_members = expected_type.members.borrow();
|
||||||
|
let expected_type = match section_members.get(¶meter.variable.name) {
|
||||||
|
Some(CircuitMemberBody::Variable(inner)) => inner,
|
||||||
|
_ => continue, // present, but unused
|
||||||
|
};
|
||||||
|
let declared_type = self.asg.borrow().scope.borrow().resolve_ast_type(¶meter.type_)?;
|
||||||
|
if !expected_type.is_assignable_from(&declared_type) {
|
||||||
|
return Err(AsgConvertError::unexpected_type(
|
||||||
|
&expected_type.to_string(),
|
||||||
|
Some(&declared_type.to_string()),
|
||||||
|
&identifier.span,
|
||||||
|
)
|
||||||
|
.into());
|
||||||
|
}
|
||||||
let member_name = parameter.variable.clone();
|
let member_name = parameter.variable.clone();
|
||||||
let member_value = self.allocate_main_function_input(
|
let member_value = self.allocate_main_function_input(
|
||||||
cs,
|
cs,
|
||||||
parameter.type_,
|
&declared_type,
|
||||||
¶meter.variable.name,
|
¶meter.variable.name,
|
||||||
option,
|
option,
|
||||||
¶meter.span,
|
¶meter.span,
|
||||||
@ -51,6 +68,6 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
|
|
||||||
// Return section as circuit expression
|
// Return section as circuit expression
|
||||||
|
|
||||||
Ok(ConstrainedValue::CircuitExpression(identifier, members))
|
Ok(ConstrainedValue::CircuitExpression(expected_type, members))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,8 +30,8 @@ use crate::{
|
|||||||
Integer,
|
Integer,
|
||||||
};
|
};
|
||||||
|
|
||||||
use leo_ast::{InputValue, Span, Type};
|
use leo_asg::Type;
|
||||||
|
use leo_ast::{InputValue, Span};
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
gadgets::r1cs::ConstraintSystem,
|
gadgets::r1cs::ConstraintSystem,
|
||||||
@ -41,7 +41,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
pub fn allocate_main_function_input<CS: ConstraintSystem<F>>(
|
pub fn allocate_main_function_input<CS: ConstraintSystem<F>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
type_: Type,
|
type_: &Type,
|
||||||
name: &str,
|
name: &str,
|
||||||
input_option: Option<InputValue>,
|
input_option: Option<InputValue>,
|
||||||
span: &Span,
|
span: &Span,
|
||||||
@ -51,14 +51,14 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
Type::Boolean => Ok(bool_from_input(cs, name, input_option, span)?),
|
Type::Boolean => Ok(bool_from_input(cs, name, input_option, span)?),
|
||||||
Type::Field => Ok(field_from_input(cs, name, input_option, span)?),
|
Type::Field => Ok(field_from_input(cs, name, input_option, span)?),
|
||||||
Type::Group => Ok(group_from_input(cs, name, input_option, span)?),
|
Type::Group => Ok(group_from_input(cs, name, input_option, span)?),
|
||||||
Type::IntegerType(integer_type) => Ok(ConstrainedValue::Integer(Integer::from_input(
|
Type::Integer(integer_type) => Ok(ConstrainedValue::Integer(Integer::from_input(
|
||||||
cs,
|
cs,
|
||||||
integer_type,
|
integer_type,
|
||||||
name,
|
name,
|
||||||
input_option,
|
input_option,
|
||||||
span,
|
span,
|
||||||
)?)),
|
)?)),
|
||||||
Type::Array(type_, dimensions) => self.allocate_array(cs, name, *type_, dimensions, input_option, span),
|
Type::Array(type_, len) => self.allocate_array(cs, name, &*type_, *len, input_option, span),
|
||||||
Type::Tuple(types) => self.allocate_tuple(cs, &name, types, input_option, span),
|
Type::Tuple(types) => self.allocate_tuple(cs, &name, types, input_option, span),
|
||||||
_ => unimplemented!("main function input not implemented for type"),
|
_ => unimplemented!("main function input not implemented for type"),
|
||||||
}
|
}
|
||||||
|
@ -19,9 +19,6 @@
|
|||||||
pub mod array;
|
pub mod array;
|
||||||
pub use self::array::*;
|
pub use self::array::*;
|
||||||
|
|
||||||
pub mod function_input;
|
|
||||||
pub use self::function_input::*;
|
|
||||||
|
|
||||||
pub mod main_function_input;
|
pub mod main_function_input;
|
||||||
pub use self::main_function_input::*;
|
pub use self::main_function_input::*;
|
||||||
|
|
||||||
|
@ -16,14 +16,10 @@
|
|||||||
|
|
||||||
//! Allocates an array as a main function input parameter in a compiled Leo program.
|
//! Allocates an array as a main function input parameter in a compiled Leo program.
|
||||||
|
|
||||||
use crate::{
|
use crate::{errors::FunctionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
||||||
errors::FunctionError,
|
|
||||||
program::{new_scope, ConstrainedProgram},
|
|
||||||
value::ConstrainedValue,
|
|
||||||
GroupType,
|
|
||||||
};
|
|
||||||
|
|
||||||
use leo_ast::{InputValue, Span, Type};
|
use leo_asg::Type;
|
||||||
|
use leo_ast::{InputValue, Span};
|
||||||
|
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
@ -35,7 +31,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
name: &str,
|
name: &str,
|
||||||
types: Vec<Type>,
|
types: &[Type],
|
||||||
input_value: Option<InputValue>,
|
input_value: Option<InputValue>,
|
||||||
span: &Span,
|
span: &Span,
|
||||||
) -> Result<ConstrainedValue<F, G>, FunctionError> {
|
) -> Result<ConstrainedValue<F, G>, FunctionError> {
|
||||||
@ -44,16 +40,16 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
match input_value {
|
match input_value {
|
||||||
Some(InputValue::Tuple(values)) => {
|
Some(InputValue::Tuple(values)) => {
|
||||||
// Allocate each value in the tuple
|
// Allocate each value in the tuple
|
||||||
for (i, (value, type_)) in values.into_iter().zip(types.into_iter()).enumerate() {
|
for (i, (value, type_)) in values.into_iter().zip(types.iter()).enumerate() {
|
||||||
let value_name = new_scope(name, &i.to_string());
|
let value_name = format!("{}_{}", &name, &i.to_string());
|
||||||
|
|
||||||
tuple_values.push(self.allocate_main_function_input(cs, type_, &value_name, Some(value), span)?)
|
tuple_values.push(self.allocate_main_function_input(cs, type_, &value_name, Some(value), span)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
// Allocate all tuple values as none
|
// Allocate all tuple values as none
|
||||||
for (i, type_) in types.into_iter().enumerate() {
|
for (i, type_) in types.iter().enumerate() {
|
||||||
let value_name = new_scope(name, &i.to_string());
|
let value_name = format!("{}_{}", &name, &i.to_string());
|
||||||
|
|
||||||
tuple_values.push(self.allocate_main_function_input(cs, type_, &value_name, None, span)?);
|
tuple_values.push(self.allocate_main_function_input(cs, type_, &value_name, None, span)?);
|
||||||
}
|
}
|
||||||
|
@ -16,14 +16,11 @@
|
|||||||
|
|
||||||
//! Enforces constraints on the main function of a compiled Leo program.
|
//! Enforces constraints on the main function of a compiled Leo program.
|
||||||
|
|
||||||
use crate::{
|
use crate::{errors::FunctionError, program::ConstrainedProgram, GroupType, OutputBytes};
|
||||||
errors::FunctionError,
|
|
||||||
program::{new_scope, ConstrainedProgram},
|
|
||||||
GroupType,
|
|
||||||
OutputBytes,
|
|
||||||
};
|
|
||||||
|
|
||||||
use leo_ast::{Expression, Function, FunctionInput, Identifier, Input};
|
use leo_asg::{Expression, FunctionBody, FunctionQualifier};
|
||||||
|
use leo_ast::Input;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
@ -34,49 +31,67 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
pub fn enforce_main_function<CS: ConstraintSystem<F>>(
|
pub fn enforce_main_function<CS: ConstraintSystem<F>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
scope: &str,
|
function: &Arc<FunctionBody>,
|
||||||
function: Function,
|
|
||||||
input: &Input,
|
input: &Input,
|
||||||
) -> Result<OutputBytes, FunctionError> {
|
) -> Result<OutputBytes, FunctionError> {
|
||||||
let function_name = new_scope(scope, function.get_name());
|
|
||||||
let registers = input.get_registers();
|
let registers = input.get_registers();
|
||||||
|
|
||||||
// Iterate over main function input variables and allocate new values
|
// 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 {
|
||||||
for input_model in function.input.clone().into_iter() {
|
// let input_var = function.scope.
|
||||||
let (input_id, value) = match input_model {
|
let asg_input = function
|
||||||
FunctionInput::InputKeyword(keyword) => {
|
.scope
|
||||||
let input_id = Identifier::new_with_span(&keyword.to_string(), &keyword.span);
|
.borrow()
|
||||||
let value = self.allocate_input_keyword(cs, keyword, input)?;
|
.resolve_input()
|
||||||
|
.expect("no input variable in scope when function is qualified");
|
||||||
|
|
||||||
(input_id, value)
|
let value = self.allocate_input_keyword(
|
||||||
}
|
cs,
|
||||||
FunctionInput::SelfKeyword(_) => unimplemented!("cannot access self keyword in main function"),
|
function.function.name.borrow().span.clone(),
|
||||||
FunctionInput::MutSelfKeyword(_) => unimplemented!("cannot access mut self keyword in main function"),
|
&asg_input.container_circuit,
|
||||||
FunctionInput::Variable(input_model) => {
|
input,
|
||||||
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(asg_input.container.borrow().id, value);
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Store input as variable with {function_name}_{identifier_name}
|
|
||||||
let input_name = new_scope(&function_name, &input_id.to_string());
|
|
||||||
|
|
||||||
// Store a new variable for every allocated main function input
|
|
||||||
self.store(input_name, value);
|
|
||||||
|
|
||||||
input_variables.push(Expression::Identifier(input_id));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let span = function.span.clone();
|
match function.function.qualifier {
|
||||||
let result_value = self.enforce_function(cs, scope, &function_name, function, input_variables, "")?;
|
FunctionQualifier::SelfRef | FunctionQualifier::MutSelfRef => {
|
||||||
let output_bytes = OutputBytes::new_from_constrained_value(registers, result_value, span)?;
|
unimplemented!("cannot access self variable in main function")
|
||||||
|
}
|
||||||
|
FunctionQualifier::Static => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut arguments = vec![];
|
||||||
|
|
||||||
|
for input_variable in function.arguments.iter() {
|
||||||
|
{
|
||||||
|
let input_variable = input_variable.borrow();
|
||||||
|
let name = input_variable.name.name.clone();
|
||||||
|
let input_option = input.get(&name).ok_or_else(|| {
|
||||||
|
FunctionError::input_not_found(name.clone(), function.span.clone().unwrap_or_default())
|
||||||
|
})?;
|
||||||
|
let input_value = self.allocate_main_function_input(
|
||||||
|
cs,
|
||||||
|
&input_variable.type_,
|
||||||
|
&name,
|
||||||
|
input_option,
|
||||||
|
&function.span.clone().unwrap_or_default(),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Store a new variable for every allocated main function input
|
||||||
|
self.store(input_variable.id, input_value);
|
||||||
|
}
|
||||||
|
arguments.push(Arc::new(Expression::VariableRef(leo_asg::VariableRef {
|
||||||
|
parent: std::cell::RefCell::new(None),
|
||||||
|
span: Some(input_variable.borrow().name.span.clone()),
|
||||||
|
variable: input_variable.clone(),
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
|
||||||
|
let span = function.span.clone().unwrap_or_default();
|
||||||
|
let result_value = self.enforce_function(cs, function, None, &arguments)?;
|
||||||
|
let output_bytes = OutputBytes::new_from_constrained_value(&self.asg, registers, result_value, span)?;
|
||||||
|
|
||||||
Ok(output_bytes)
|
Ok(output_bytes)
|
||||||
}
|
}
|
||||||
|
@ -27,3 +27,6 @@ pub use self::main_function::*;
|
|||||||
|
|
||||||
pub mod result;
|
pub mod result;
|
||||||
pub use self::result::*;
|
pub use self::result::*;
|
||||||
|
|
||||||
|
pub mod mut_target;
|
||||||
|
pub use self::mut_target::*;
|
||||||
|
124
compiler/src/function/mut_target.rs
Normal file
124
compiler/src/function/mut_target.rs
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||||
|
// This file is part of the Leo library.
|
||||||
|
|
||||||
|
// The Leo library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// The Leo library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Resolves assignees in a compiled Leo program.
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
errors::StatementError,
|
||||||
|
program::ConstrainedProgram,
|
||||||
|
value::ConstrainedValue,
|
||||||
|
GroupType,
|
||||||
|
ResolvedAssigneeAccess,
|
||||||
|
};
|
||||||
|
use leo_asg::{
|
||||||
|
ArrayAccessExpression,
|
||||||
|
ArrayRangeAccessExpression,
|
||||||
|
CircuitAccessExpression,
|
||||||
|
Expression,
|
||||||
|
Node,
|
||||||
|
Span,
|
||||||
|
TupleAccessExpression,
|
||||||
|
Variable,
|
||||||
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use snarkvm_models::{
|
||||||
|
curves::{Field, PrimeField},
|
||||||
|
gadgets::r1cs::ConstraintSystem,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||||
|
fn prepare_mut_access<CS: ConstraintSystem<F>>(
|
||||||
|
&mut self,
|
||||||
|
cs: &mut CS,
|
||||||
|
expr: &Arc<Expression>,
|
||||||
|
span: &Span,
|
||||||
|
output: &mut Vec<ResolvedAssigneeAccess>,
|
||||||
|
) -> Result<Option<Variable>, StatementError> {
|
||||||
|
match &**expr {
|
||||||
|
Expression::ArrayRangeAccess(ArrayRangeAccessExpression { array, left, right, .. }) => {
|
||||||
|
let inner = self.prepare_mut_access(cs, array, span, output)?;
|
||||||
|
let start_index = left
|
||||||
|
.as_ref()
|
||||||
|
.map(|start| self.enforce_index(cs, start, &span))
|
||||||
|
.transpose()?;
|
||||||
|
let stop_index = right
|
||||||
|
.as_ref()
|
||||||
|
.map(|stop| self.enforce_index(cs, stop, &span))
|
||||||
|
.transpose()?;
|
||||||
|
|
||||||
|
output.push(ResolvedAssigneeAccess::ArrayRange(start_index, stop_index));
|
||||||
|
Ok(inner)
|
||||||
|
}
|
||||||
|
Expression::ArrayAccess(ArrayAccessExpression { array, index, .. }) => {
|
||||||
|
let inner = self.prepare_mut_access(cs, array, span, output)?;
|
||||||
|
let index = self.enforce_index(cs, index, &span)?;
|
||||||
|
|
||||||
|
output.push(ResolvedAssigneeAccess::ArrayIndex(index));
|
||||||
|
Ok(inner)
|
||||||
|
}
|
||||||
|
Expression::TupleAccess(TupleAccessExpression { tuple_ref, index, .. }) => {
|
||||||
|
let inner = self.prepare_mut_access(cs, tuple_ref, span, output)?;
|
||||||
|
|
||||||
|
output.push(ResolvedAssigneeAccess::Tuple(*index, span.clone()));
|
||||||
|
Ok(inner)
|
||||||
|
}
|
||||||
|
Expression::CircuitAccess(CircuitAccessExpression {
|
||||||
|
target: Some(target),
|
||||||
|
member,
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
let inner = self.prepare_mut_access(cs, target, span, output)?;
|
||||||
|
|
||||||
|
output.push(ResolvedAssigneeAccess::Member(member.clone()));
|
||||||
|
Ok(inner)
|
||||||
|
}
|
||||||
|
Expression::VariableRef(variable_ref) => Ok(Some(variable_ref.variable.clone())),
|
||||||
|
_ => Ok(None), // not a valid reference to mutable variable, we copy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolve a mutable reference from an expression
|
||||||
|
// return Ok(None) if no valid mutable reference, or Err(_) on more critical error
|
||||||
|
pub fn resolve_mut_ref<CS: ConstraintSystem<F>>(
|
||||||
|
&mut self,
|
||||||
|
cs: &mut CS,
|
||||||
|
assignee: &Arc<Expression>,
|
||||||
|
) -> Result<Option<Vec<&mut ConstrainedValue<F, G>>>, StatementError> {
|
||||||
|
let span = assignee.span().cloned().unwrap_or_default();
|
||||||
|
|
||||||
|
let mut accesses = vec![];
|
||||||
|
let target = self.prepare_mut_access(cs, assignee, &span, &mut accesses)?;
|
||||||
|
if target.is_none() {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
let variable = target.unwrap();
|
||||||
|
let variable = variable.borrow();
|
||||||
|
|
||||||
|
let mut result = vec![match self.get_mut(&variable.id) {
|
||||||
|
Some(value) => match value {
|
||||||
|
ConstrainedValue::Mutable(mutable) => &mut **mutable,
|
||||||
|
_ => return Err(StatementError::immutable_assign(variable.name.to_string(), span)),
|
||||||
|
},
|
||||||
|
None => return Err(StatementError::undefined_variable(variable.name.to_string(), span)),
|
||||||
|
}];
|
||||||
|
|
||||||
|
for access in accesses {
|
||||||
|
result = Self::resolve_assignee_access(access, &span, result)?;
|
||||||
|
}
|
||||||
|
Ok(Some(result))
|
||||||
|
}
|
||||||
|
}
|
@ -17,7 +17,6 @@
|
|||||||
//! Enforces that one return value is produced in a compiled Leo program.
|
//! Enforces that one return value is produced in a compiled Leo program.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
check_return_type,
|
|
||||||
errors::StatementError,
|
errors::StatementError,
|
||||||
get_indicator_value,
|
get_indicator_value,
|
||||||
program::ConstrainedProgram,
|
program::ConstrainedProgram,
|
||||||
@ -25,7 +24,7 @@ use crate::{
|
|||||||
GroupType,
|
GroupType,
|
||||||
};
|
};
|
||||||
|
|
||||||
use leo_ast::{Span, Type};
|
use leo_asg::{Span, Type};
|
||||||
|
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
@ -42,37 +41,21 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
///
|
///
|
||||||
pub fn conditionally_select_result<CS: ConstraintSystem<F>>(
|
pub fn conditionally_select_result<CS: ConstraintSystem<F>>(
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
expected_return: Option<Type>,
|
expected_return: &Type,
|
||||||
results: Vec<(Boolean, ConstrainedValue<F, G>)>,
|
results: Vec<(Boolean, ConstrainedValue<F, G>)>,
|
||||||
span: &Span,
|
span: &Span,
|
||||||
) -> Result<ConstrainedValue<F, G>, StatementError> {
|
) -> Result<ConstrainedValue<F, G>, StatementError> {
|
||||||
// Initialize empty return value.
|
// Initialize empty return value.
|
||||||
let mut return_value = ConstrainedValue::Tuple(vec![]);
|
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.
|
// Error if the function or one of its branches does not return.
|
||||||
if results
|
if !expected_return.is_unit()
|
||||||
.iter()
|
&& results
|
||||||
.find(|(indicator, _res)| get_indicator_value(indicator))
|
.iter()
|
||||||
.is_none()
|
.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
|
// Find the return value
|
||||||
@ -81,7 +64,13 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
for (indicator, result) in results.into_iter() {
|
for (indicator, result) in results.into_iter() {
|
||||||
// Error if a statement returned a result with an incorrect type
|
// Error if a statement returned a result with an incorrect type
|
||||||
let result_type = result.to_type(span)?;
|
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) {
|
if get_indicator_value(&indicator) {
|
||||||
// Error if we already have a return value.
|
// Error if we already have a return value.
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
|
||||||
// This file is part of the Leo library.
|
|
||||||
|
|
||||||
// The Leo library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// The Leo library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
/// The import store brings an imported symbol into the main program from an import program struct
|
|
||||||
pub mod store;
|
|
||||||
pub use self::store::*;
|
|
@ -1,58 +0,0 @@
|
|||||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
|
||||||
// This file is part of the Leo library.
|
|
||||||
|
|
||||||
// The Leo library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// The Leo library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
use crate::{errors::ImportError, ConstrainedProgram, GroupType};
|
|
||||||
use leo_ast::ImportStatement;
|
|
||||||
use leo_imports::ImportParser;
|
|
||||||
use leo_symbol_table::imported_symbols::ImportedSymbols;
|
|
||||||
|
|
||||||
use snarkvm_models::curves::{Field, PrimeField};
|
|
||||||
|
|
||||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|
||||||
pub(crate) fn store_import(
|
|
||||||
&mut self,
|
|
||||||
scope: &str,
|
|
||||||
import: &ImportStatement,
|
|
||||||
imported_programs: &ImportParser,
|
|
||||||
) -> Result<(), ImportError> {
|
|
||||||
// Fetch core packages.
|
|
||||||
let core_package = imported_programs.get_core_package(&import.package);
|
|
||||||
|
|
||||||
if let Some(package) = core_package {
|
|
||||||
self.store_core_package(scope, package.clone())?;
|
|
||||||
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch dependencies for the current import
|
|
||||||
let imported_symbols = ImportedSymbols::new(import);
|
|
||||||
|
|
||||||
for (name, symbol) in imported_symbols.symbols {
|
|
||||||
// Find imported program
|
|
||||||
let program = imported_programs
|
|
||||||
.get_import(&name)
|
|
||||||
.ok_or_else(|| ImportError::unknown_package(import.package.name.clone()))?;
|
|
||||||
|
|
||||||
// Parse imported program
|
|
||||||
self.store_definitions(program, imported_programs)?;
|
|
||||||
|
|
||||||
// Store the imported symbol
|
|
||||||
self.store_symbol(scope, &name, &symbol, program)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
|
||||||
// This file is part of the Leo library.
|
|
||||||
|
|
||||||
// The Leo library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// The Leo library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
/// The import store brings an imported symbol into the main program from an import program struct
|
|
||||||
pub mod core_package;
|
|
||||||
pub use self::core_package::*;
|
|
||||||
|
|
||||||
pub mod import;
|
|
||||||
pub use self::import::*;
|
|
||||||
|
|
||||||
pub mod symbol;
|
|
||||||
pub use self::symbol::*;
|
|
@ -1,92 +0,0 @@
|
|||||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
|
||||||
// This file is part of the Leo library.
|
|
||||||
|
|
||||||
// The Leo library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// The Leo library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
use crate::{errors::ImportError, new_scope, ConstrainedProgram, ConstrainedValue, GroupType};
|
|
||||||
use leo_ast::{ImportSymbol, Program};
|
|
||||||
|
|
||||||
use snarkvm_models::curves::{Field, PrimeField};
|
|
||||||
|
|
||||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|
||||||
pub(crate) fn store_symbol(
|
|
||||||
&mut self,
|
|
||||||
scope: &str,
|
|
||||||
program_name: &str,
|
|
||||||
symbol: &ImportSymbol,
|
|
||||||
program: &Program,
|
|
||||||
) -> Result<(), ImportError> {
|
|
||||||
// Store the symbol that was imported by another file
|
|
||||||
if symbol.is_star() {
|
|
||||||
// evaluate and store all circuit definitions
|
|
||||||
program.circuits.iter().for_each(|(identifier, circuit)| {
|
|
||||||
let name = new_scope(scope, &identifier.name);
|
|
||||||
let value = ConstrainedValue::Import(
|
|
||||||
program_name.to_owned(),
|
|
||||||
Box::new(ConstrainedValue::CircuitDefinition(circuit.clone())),
|
|
||||||
);
|
|
||||||
|
|
||||||
self.store(name, value);
|
|
||||||
});
|
|
||||||
|
|
||||||
// evaluate and store all function definitions
|
|
||||||
program.functions.iter().for_each(|(identifier, function)| {
|
|
||||||
let name = new_scope(scope, &identifier.name);
|
|
||||||
let value = ConstrainedValue::Import(
|
|
||||||
program_name.to_owned(),
|
|
||||||
Box::new(ConstrainedValue::Function(None, Box::new(function.clone()))),
|
|
||||||
);
|
|
||||||
|
|
||||||
self.store(name, value);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// see if the imported symbol is a circuit
|
|
||||||
let matched_circuit = program
|
|
||||||
.circuits
|
|
||||||
.iter()
|
|
||||||
.find(|(circuit_name, _circuit_def)| symbol.symbol == **circuit_name);
|
|
||||||
|
|
||||||
let value = match matched_circuit {
|
|
||||||
Some((_circuit_name, circuit)) => ConstrainedValue::Import(
|
|
||||||
program_name.to_owned(),
|
|
||||||
Box::new(ConstrainedValue::CircuitDefinition(circuit.clone())),
|
|
||||||
),
|
|
||||||
None => {
|
|
||||||
// see if the imported symbol is a function
|
|
||||||
let matched_function = program
|
|
||||||
.functions
|
|
||||||
.iter()
|
|
||||||
.find(|(function_name, _function)| symbol.symbol == **function_name);
|
|
||||||
|
|
||||||
match matched_function {
|
|
||||||
Some((_function_name, function)) => ConstrainedValue::Import(
|
|
||||||
program_name.to_owned(),
|
|
||||||
Box::new(ConstrainedValue::Function(None, Box::new(function.clone()))),
|
|
||||||
),
|
|
||||||
None => return Err(ImportError::unknown_symbol(symbol.to_owned(), program_name.to_owned())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// take the alias if it is present
|
|
||||||
let id = symbol.alias.clone().unwrap_or_else(|| symbol.symbol.clone());
|
|
||||||
let name = new_scope(scope, &id.name);
|
|
||||||
|
|
||||||
// store imported circuit under imported name
|
|
||||||
self.store(name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
@ -41,9 +41,6 @@ pub use self::expression::*;
|
|||||||
pub mod function;
|
pub mod function;
|
||||||
pub use self::function::*;
|
pub use self::function::*;
|
||||||
|
|
||||||
pub mod import;
|
|
||||||
pub use self::import::*;
|
|
||||||
|
|
||||||
pub mod output;
|
pub mod output;
|
||||||
pub use self::output::*;
|
pub use self::output::*;
|
||||||
|
|
||||||
@ -53,5 +50,11 @@ pub use self::program::*;
|
|||||||
pub mod statement;
|
pub mod statement;
|
||||||
pub use self::statement::*;
|
pub use self::statement::*;
|
||||||
|
|
||||||
|
pub mod prelude;
|
||||||
|
pub use self::prelude::*;
|
||||||
|
|
||||||
pub mod value;
|
pub mod value;
|
||||||
pub use self::value::*;
|
pub use self::value::*;
|
||||||
|
|
||||||
|
pub mod stage;
|
||||||
|
pub use self::stage::*;
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{errors::OutputBytesError, ConstrainedValue, GroupType, REGISTERS_VARIABLE_NAME};
|
use crate::{errors::OutputBytesError, ConstrainedValue, GroupType, REGISTERS_VARIABLE_NAME};
|
||||||
|
use leo_asg::Program;
|
||||||
use leo_ast::{Parameter, Registers, Span};
|
use leo_ast::{Parameter, Registers, Span};
|
||||||
|
|
||||||
use snarkvm_models::curves::{Field, PrimeField};
|
use snarkvm_models::curves::{Field, PrimeField};
|
||||||
@ -31,6 +32,7 @@ impl OutputBytes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_from_constrained_value<F: Field + PrimeField, G: GroupType<F>>(
|
pub fn new_from_constrained_value<F: Field + PrimeField, G: GroupType<F>>(
|
||||||
|
program: &Program,
|
||||||
registers: &Registers,
|
registers: &Registers,
|
||||||
value: ConstrainedValue<F, G>,
|
value: ConstrainedValue<F, G>,
|
||||||
span: Span,
|
span: Span,
|
||||||
@ -65,13 +67,13 @@ impl OutputBytes {
|
|||||||
let name = parameter.variable.name;
|
let name = parameter.variable.name;
|
||||||
|
|
||||||
// Check register type == return value type.
|
// Check register type == return value type.
|
||||||
let register_type = parameter.type_;
|
let register_type = program.borrow().scope.borrow().resolve_ast_type(¶meter.type_)?;
|
||||||
let return_value_type = value.to_type(&span)?;
|
let return_value_type = value.to_type(&span)?;
|
||||||
|
|
||||||
if !register_type.eq_flat(&return_value_type) {
|
if !register_type.is_assignable_from(&return_value_type) {
|
||||||
return Err(OutputBytesError::mismatched_output_types(
|
return Err(OutputBytesError::mismatched_output_types(
|
||||||
register_type,
|
®ister_type,
|
||||||
return_value_type,
|
&return_value_type,
|
||||||
span,
|
span,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
82
compiler/src/prelude/blake2s.rs
Normal file
82
compiler/src/prelude/blake2s.rs
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||||
|
// This file is part of the Leo library.
|
||||||
|
|
||||||
|
// The Leo library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// The Leo library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use super::CoreCircuit;
|
||||||
|
use crate::{errors::ExpressionError, ConstrainedValue, GroupType, Integer};
|
||||||
|
use leo_asg::{FunctionBody, Span};
|
||||||
|
use snarkvm_gadgets::algorithms::prf::Blake2sGadget;
|
||||||
|
use snarkvm_models::{
|
||||||
|
curves::{Field, PrimeField},
|
||||||
|
gadgets::{
|
||||||
|
algorithms::PRFGadget,
|
||||||
|
r1cs::ConstraintSystem,
|
||||||
|
utilities::{uint::UInt8, ToBytesGadget},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Blake2s;
|
||||||
|
|
||||||
|
fn unwrap_argument<F: Field + PrimeField, G: GroupType<F>>(mut arg: ConstrainedValue<F, G>) -> Vec<UInt8> {
|
||||||
|
arg.get_inner_mut();
|
||||||
|
if let ConstrainedValue::Array(args) = arg {
|
||||||
|
assert_eq!(args.len(), 32); // asg enforced
|
||||||
|
args.into_iter()
|
||||||
|
.map(|item| {
|
||||||
|
if let ConstrainedValue::Integer(Integer::U8(item)) = item {
|
||||||
|
item
|
||||||
|
} else {
|
||||||
|
panic!("illegal non-u8 type in blake2s call");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
} else {
|
||||||
|
panic!("illegal non-array type in blake2s call");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F: Field + PrimeField, G: GroupType<F>> CoreCircuit<F, G> for Blake2s {
|
||||||
|
fn call_function<CS: ConstraintSystem<F>>(
|
||||||
|
&self,
|
||||||
|
cs: &mut CS,
|
||||||
|
function: Arc<FunctionBody>,
|
||||||
|
span: &Span,
|
||||||
|
target: Option<ConstrainedValue<F, G>>,
|
||||||
|
mut arguments: Vec<ConstrainedValue<F, G>>,
|
||||||
|
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||||
|
assert_eq!(arguments.len(), 2); // asg enforced
|
||||||
|
assert!(function.function.name.borrow().name == "hash"); // asg enforced
|
||||||
|
assert!(target.is_none()); // asg enforced
|
||||||
|
let input = unwrap_argument(arguments.remove(1));
|
||||||
|
let seed = unwrap_argument(arguments.remove(0));
|
||||||
|
|
||||||
|
let digest =
|
||||||
|
Blake2sGadget::check_evaluation_gadget(cs.ns(|| "blake2s hash"), &seed[..], &input[..]).map_err(|e| {
|
||||||
|
ExpressionError::cannot_enforce("Blake2s check evaluation gadget".to_owned(), e, span.clone())
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(ConstrainedValue::Array(
|
||||||
|
digest
|
||||||
|
.to_bytes(cs)
|
||||||
|
.map_err(|e| ExpressionError::cannot_enforce("Vec<UInt8> ToBytes".to_owned(), e, span.clone()))?
|
||||||
|
.into_iter()
|
||||||
|
.map(Integer::U8)
|
||||||
|
.map(ConstrainedValue::Integer)
|
||||||
|
.collect(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
@ -14,28 +14,32 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{CoreCircuitError, Value};
|
pub mod blake2s;
|
||||||
use leo_ast::{Circuit, Identifier, Span};
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub use blake2s::*;
|
||||||
|
|
||||||
|
use crate::{errors::ExpressionError, ConstrainedValue, GroupType};
|
||||||
|
use leo_asg::{FunctionBody, Span};
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
gadgets::r1cs::ConstraintSystem,
|
gadgets::r1cs::ConstraintSystem,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A core circuit type, accessible to all Leo programs by default.
|
pub trait CoreCircuit<F: Field + PrimeField, G: GroupType<F>>: Send + Sync {
|
||||||
/// To access a `CoreCircuit`, import its symbol from a `CorePackage`.
|
fn call_function<CS: ConstraintSystem<F>>(
|
||||||
pub trait CoreCircuit {
|
&self,
|
||||||
/// The name of the core circuit function
|
cs: &mut CS,
|
||||||
fn name() -> String;
|
function: Arc<FunctionBody>,
|
||||||
|
span: &Span,
|
||||||
/// Return the abstract syntax tree representation of the core circuit for compiler parsing.
|
target: Option<ConstrainedValue<F, G>>,
|
||||||
fn ast(circuit_name: Identifier, span: Span) -> Circuit;
|
arguments: Vec<ConstrainedValue<F, G>>,
|
||||||
|
) -> Result<ConstrainedValue<F, G>, ExpressionError>;
|
||||||
/// Call the gadget associated with this core circuit with arguments.
|
}
|
||||||
/// Generate constraints on the given `ConstraintSystem`.
|
|
||||||
fn call<F: Field + PrimeField, CS: ConstraintSystem<F>>(
|
pub fn resolve_core_circuit<F: Field + PrimeField, G: GroupType<F>>(name: &str) -> impl CoreCircuit<F, G> {
|
||||||
cs: CS,
|
match name {
|
||||||
arguments: Vec<Value>,
|
"blake2s" => Blake2s,
|
||||||
span: Span,
|
_ => unimplemented!("invalid core circuit: {}", name),
|
||||||
) -> Result<Vec<Value>, CoreCircuitError>;
|
}
|
||||||
}
|
}
|
@ -18,44 +18,34 @@
|
|||||||
|
|
||||||
use crate::{value::ConstrainedValue, GroupType};
|
use crate::{value::ConstrainedValue, GroupType};
|
||||||
|
|
||||||
|
use leo_asg::Program;
|
||||||
use snarkvm_models::curves::{Field, PrimeField};
|
use snarkvm_models::curves::{Field, PrimeField};
|
||||||
|
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
pub struct ConstrainedProgram<F: Field + PrimeField, G: GroupType<F>> {
|
pub struct ConstrainedProgram<F: Field + PrimeField, G: GroupType<F>> {
|
||||||
pub identifiers: IndexMap<String, ConstrainedValue<F, G>>,
|
pub asg: Program,
|
||||||
}
|
identifiers: IndexMap<Uuid, ConstrainedValue<F, G>>,
|
||||||
|
|
||||||
impl<F: Field + PrimeField, G: GroupType<F>> Default for ConstrainedProgram<F, G> {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
identifiers: IndexMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_scope(outer: &str, inner: &str) -> String {
|
|
||||||
format!("{}_{}", outer, inner)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_in_scope(current_scope: &str, desired_scope: &str) -> bool {
|
|
||||||
current_scope.ends_with(desired_scope)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||||
pub fn new() -> Self {
|
pub fn new(asg: Program) -> Self {
|
||||||
Self::default()
|
Self {
|
||||||
|
asg,
|
||||||
|
identifiers: IndexMap::new(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn store(&mut self, name: String, value: ConstrainedValue<F, G>) {
|
pub(crate) fn store(&mut self, name: Uuid, value: ConstrainedValue<F, G>) {
|
||||||
self.identifiers.insert(name, value);
|
self.identifiers.insert(name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get(&self, name: &str) -> Option<&ConstrainedValue<F, G>> {
|
pub(crate) fn get(&self, name: &Uuid) -> Option<&ConstrainedValue<F, G>> {
|
||||||
self.identifiers.get(name)
|
self.identifiers.get(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_mut(&mut self, name: &str) -> Option<&mut ConstrainedValue<F, G>> {
|
pub(crate) fn get_mut(&mut self, name: &Uuid) -> Option<&mut ConstrainedValue<F, G>> {
|
||||||
self.identifiers.get_mut(name)
|
self.identifiers.get_mut(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,5 +14,8 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
pub mod blake2s;
|
use leo_asg::Program;
|
||||||
pub use self::blake2s::*;
|
|
||||||
|
pub trait ASGStage {
|
||||||
|
fn apply(asg: &mut Program);
|
||||||
|
}
|
@ -16,15 +16,8 @@
|
|||||||
|
|
||||||
//! Enforces an assign statement in a compiled Leo program.
|
//! Enforces an assign statement in a compiled Leo program.
|
||||||
|
|
||||||
use crate::{
|
use crate::{arithmetic::*, errors::StatementError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
||||||
arithmetic::*,
|
use leo_asg::{AssignOperation, AssignStatement, Span};
|
||||||
errors::StatementError,
|
|
||||||
new_scope,
|
|
||||||
program::ConstrainedProgram,
|
|
||||||
value::ConstrainedValue,
|
|
||||||
GroupType,
|
|
||||||
};
|
|
||||||
use leo_ast::{AssignOperation, AssignStatement, AssigneeAccess, Span};
|
|
||||||
|
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
@ -39,28 +32,15 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
pub fn enforce_assign_statement<CS: ConstraintSystem<F>>(
|
pub fn enforce_assign_statement<CS: ConstraintSystem<F>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: &str,
|
|
||||||
function_scope: &str,
|
|
||||||
declared_circuit_reference: &str,
|
|
||||||
indicator: &Boolean,
|
indicator: &Boolean,
|
||||||
mut_self: bool,
|
statement: &AssignStatement,
|
||||||
statement: AssignStatement,
|
|
||||||
) -> Result<(), StatementError> {
|
) -> Result<(), StatementError> {
|
||||||
// Get the name of the variable we are assigning to
|
// 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 new_value = self.enforce_expression(cs, &statement.value)?;
|
||||||
let mut resolved_assignee = self.resolve_assignee(
|
let mut resolved_assignee = self.resolve_assign(cs, statement)?;
|
||||||
cs,
|
|
||||||
file_scope,
|
|
||||||
function_scope,
|
|
||||||
declared_circuit_reference,
|
|
||||||
mut_self,
|
|
||||||
statement.assignee.clone(),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
if resolved_assignee.len() == 1 {
|
if resolved_assignee.len() == 1 {
|
||||||
new_value.resolve_type(Some(resolved_assignee[0].to_type(&statement.span)?), &statement.span)?;
|
let span = statement.span.clone().unwrap_or_default();
|
||||||
|
|
||||||
let span = statement.span.clone();
|
|
||||||
|
|
||||||
Self::enforce_assign_operation(
|
Self::enforce_assign_operation(
|
||||||
cs,
|
cs,
|
||||||
@ -74,7 +54,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
} else {
|
} else {
|
||||||
match new_value {
|
match new_value {
|
||||||
ConstrainedValue::Array(new_values) => {
|
ConstrainedValue::Array(new_values) => {
|
||||||
let span = statement.span.clone();
|
let span = statement.span.clone().unwrap_or_default();
|
||||||
|
|
||||||
for (i, (old_ref, new_value)) in
|
for (i, (old_ref, new_value)) in
|
||||||
resolved_assignee.into_iter().zip(new_values.into_iter()).enumerate()
|
resolved_assignee.into_iter().zip(new_values.into_iter()).enumerate()
|
||||||
@ -90,35 +70,12 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => 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(())
|
Ok(())
|
||||||
@ -130,11 +87,9 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
scope: String,
|
scope: String,
|
||||||
operation: &AssignOperation,
|
operation: &AssignOperation,
|
||||||
target: &mut ConstrainedValue<F, G>,
|
target: &mut ConstrainedValue<F, G>,
|
||||||
mut new_value: ConstrainedValue<F, G>,
|
new_value: ConstrainedValue<F, G>,
|
||||||
span: &Span,
|
span: &Span,
|
||||||
) -> Result<(), StatementError> {
|
) -> Result<(), StatementError> {
|
||||||
new_value.resolve_type(Some(target.to_type(span)?), span)?;
|
|
||||||
|
|
||||||
let new_value = match operation {
|
let new_value = match operation {
|
||||||
AssignOperation::Assign => new_value,
|
AssignOperation::Assign => new_value,
|
||||||
AssignOperation::Add => enforce_add(cs, target.clone(), new_value, span)?,
|
AssignOperation::Add => enforce_add(cs, target.clone(), new_value, span)?,
|
||||||
|
@ -16,79 +16,62 @@
|
|||||||
|
|
||||||
//! Resolves assignees in a compiled Leo program.
|
//! Resolves assignees in a compiled Leo program.
|
||||||
|
|
||||||
use crate::{
|
use crate::{errors::StatementError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
||||||
errors::StatementError,
|
use leo_asg::{AssignAccess, AssignStatement, Identifier, Span};
|
||||||
new_scope,
|
|
||||||
parse_index,
|
|
||||||
program::ConstrainedProgram,
|
|
||||||
value::ConstrainedValue,
|
|
||||||
GroupType,
|
|
||||||
};
|
|
||||||
use leo_ast::{Assignee, AssigneeAccess, Identifier, PositiveNumber, Span};
|
|
||||||
|
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
gadgets::r1cs::ConstraintSystem,
|
gadgets::r1cs::ConstraintSystem,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ResolvedAssigneeAccess {
|
pub(crate) enum ResolvedAssigneeAccess {
|
||||||
ArrayRange(Option<usize>, Option<usize>),
|
ArrayRange(Option<usize>, Option<usize>),
|
||||||
ArrayIndex(usize),
|
ArrayIndex(usize),
|
||||||
Tuple(PositiveNumber, Span),
|
Tuple(usize, Span),
|
||||||
Member(Identifier),
|
Member(Identifier),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||||
pub fn resolve_assignee<CS: ConstraintSystem<F>>(
|
pub fn resolve_assign<CS: ConstraintSystem<F>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: &str,
|
assignee: &AssignStatement,
|
||||||
function_scope: &str,
|
|
||||||
declared_circuit_reference: &str,
|
|
||||||
mut_self: bool,
|
|
||||||
assignee: Assignee,
|
|
||||||
) -> Result<Vec<&mut ConstrainedValue<F, G>>, StatementError> {
|
) -> Result<Vec<&mut ConstrainedValue<F, G>>, StatementError> {
|
||||||
let value_ref = if assignee.identifier.is_self() {
|
let span = assignee.span.clone().unwrap_or_default();
|
||||||
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 resolved_accesses = assignee
|
let resolved_accesses = assignee
|
||||||
.accesses
|
.target_accesses
|
||||||
.into_iter()
|
.iter()
|
||||||
.map(|access| match access {
|
.map(|access| match access {
|
||||||
AssigneeAccess::ArrayRange(start, stop) => {
|
AssignAccess::ArrayRange(start, stop) => {
|
||||||
let start_index = start
|
let start_index = start
|
||||||
.map(|start| self.enforce_index(cs, file_scope, function_scope, start, &span))
|
.as_ref()
|
||||||
|
.map(|start| self.enforce_index(cs, start, &span))
|
||||||
.transpose()?;
|
.transpose()?;
|
||||||
let stop_index = stop
|
let stop_index = stop
|
||||||
.map(|stop| self.enforce_index(cs, file_scope, function_scope, stop, &span))
|
.as_ref()
|
||||||
|
.map(|stop| self.enforce_index(cs, stop, &span))
|
||||||
.transpose()?;
|
.transpose()?;
|
||||||
Ok(ResolvedAssigneeAccess::ArrayRange(start_index, stop_index))
|
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)?;
|
let index = self.enforce_index(cs, index, &span)?;
|
||||||
|
|
||||||
Ok(ResolvedAssigneeAccess::ArrayIndex(index))
|
Ok(ResolvedAssigneeAccess::ArrayIndex(index))
|
||||||
}
|
}
|
||||||
AssigneeAccess::Tuple(index, span) => Ok(ResolvedAssigneeAccess::Tuple(index, span)),
|
AssignAccess::Tuple(index) => Ok(ResolvedAssigneeAccess::Tuple(*index, span.clone())),
|
||||||
AssigneeAccess::Member(identifier) => Ok(ResolvedAssigneeAccess::Member(identifier)),
|
AssignAccess::Member(identifier) => Ok(ResolvedAssigneeAccess::Member(identifier.clone())),
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>, crate::errors::ExpressionError>>()?;
|
.collect::<Result<Vec<_>, 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 {
|
Some(value) => match value {
|
||||||
ConstrainedValue::Mutable(mutable) => &mut **mutable,
|
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 {
|
for access in resolved_accesses {
|
||||||
@ -121,12 +104,13 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
// discards unnecessary mutable wrappers
|
// discards unnecessary mutable wrappers
|
||||||
fn unwrap_mutable(input: &mut ConstrainedValue<F, G>) -> &mut ConstrainedValue<F, G> {
|
fn unwrap_mutable(input: &mut ConstrainedValue<F, G>) -> &mut ConstrainedValue<F, G> {
|
||||||
match input {
|
match input {
|
||||||
ConstrainedValue::Mutable(x) => &mut **x,
|
ConstrainedValue::Mutable(x) => Self::unwrap_mutable(&mut **x),
|
||||||
x => x,
|
x => x,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_assignee_access<'a>(
|
// todo: this can prob have most of its error checking removed
|
||||||
|
pub(crate) fn resolve_assignee_access<'a>(
|
||||||
access: ResolvedAssigneeAccess,
|
access: ResolvedAssigneeAccess,
|
||||||
span: &Span,
|
span: &Span,
|
||||||
mut value: Vec<&'a mut ConstrainedValue<F, G>>,
|
mut value: Vec<&'a mut ConstrainedValue<F, G>>,
|
||||||
@ -174,8 +158,6 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ResolvedAssigneeAccess::Tuple(index, span) => {
|
ResolvedAssigneeAccess::Tuple(index, span) => {
|
||||||
let index = parse_index(&index, &span)?;
|
|
||||||
|
|
||||||
if value.len() != 1 {
|
if value.len() != 1 {
|
||||||
return Err(StatementError::array_assign_interior_index(span));
|
return Err(StatementError::array_assign_interior_index(span));
|
||||||
}
|
}
|
||||||
@ -200,23 +182,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
let matched_variable = members.iter_mut().find(|member| member.0 == name);
|
let matched_variable = members.iter_mut().find(|member| member.0 == name);
|
||||||
|
|
||||||
match matched_variable {
|
match matched_variable {
|
||||||
Some(member) => match &mut member.1 {
|
Some(member) => Ok(vec![&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 => {
|
None => {
|
||||||
// Throw an error if the circuit variable does not exist in the circuit
|
// Throw an error if the circuit variable does not exist in the circuit
|
||||||
Err(StatementError::undefined_circuit_variable(
|
Err(StatementError::undefined_circuit_variable(
|
||||||
@ -227,30 +193,9 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Throw an error if the circuit definition does not exist in the file
|
// Throw an error if the circuit definition does not exist in the file
|
||||||
_ => Err(StatementError::undefined_circuit(name.to_string(), span.to_owned())),
|
x => Err(StatementError::undefined_circuit(x.to_string(), span.to_owned())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_mutable_assignee(
|
|
||||||
&mut self,
|
|
||||||
name: &str,
|
|
||||||
span: &Span,
|
|
||||||
) -> Result<&mut ConstrainedValue<F, G>, 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())),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -20,4 +20,4 @@ pub mod assign;
|
|||||||
pub use self::assign::*;
|
pub use self::assign::*;
|
||||||
|
|
||||||
pub mod assignee;
|
pub mod assignee;
|
||||||
pub use self::assignee::*;
|
pub(crate) use self::assignee::*;
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
//! Enforces a branch of a conditional or iteration statement in a compiled Leo program.
|
//! Enforces a branch of a conditional or iteration statement in a compiled Leo program.
|
||||||
|
|
||||||
use crate::{program::ConstrainedProgram, GroupType, IndicatorAndConstrainedValue, StatementResult};
|
use crate::{program::ConstrainedProgram, GroupType, IndicatorAndConstrainedValue, StatementResult};
|
||||||
use leo_ast::{Block, Type};
|
use leo_asg::BlockStatement;
|
||||||
|
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
@ -31,27 +31,13 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
pub fn evaluate_block<CS: ConstraintSystem<F>>(
|
pub fn evaluate_block<CS: ConstraintSystem<F>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: &str,
|
|
||||||
function_scope: &str,
|
|
||||||
indicator: &Boolean,
|
indicator: &Boolean,
|
||||||
block: Block,
|
block: &BlockStatement,
|
||||||
return_type: Option<Type>,
|
|
||||||
declared_circuit_reference: &str,
|
|
||||||
mut_self: bool,
|
|
||||||
) -> StatementResult<Vec<IndicatorAndConstrainedValue<F, G>>> {
|
) -> StatementResult<Vec<IndicatorAndConstrainedValue<F, G>>> {
|
||||||
let mut results = Vec::with_capacity(block.statements.len());
|
let mut results = Vec::with_capacity(block.statements.len());
|
||||||
// Evaluate statements. Only allow a single return argument to be returned.
|
// 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(
|
let value = self.enforce_statement(cs, indicator, statement)?;
|
||||||
cs,
|
|
||||||
file_scope,
|
|
||||||
function_scope,
|
|
||||||
indicator,
|
|
||||||
statement,
|
|
||||||
return_type.clone(),
|
|
||||||
declared_circuit_reference,
|
|
||||||
mut_self,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
results.extend(value);
|
results.extend(value);
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ use crate::{
|
|||||||
IndicatorAndConstrainedValue,
|
IndicatorAndConstrainedValue,
|
||||||
StatementResult,
|
StatementResult,
|
||||||
};
|
};
|
||||||
use leo_ast::{ConditionalStatement, Type};
|
use leo_asg::ConditionalStatement;
|
||||||
|
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
@ -47,33 +47,18 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
pub fn enforce_conditional_statement<CS: ConstraintSystem<F>>(
|
pub fn enforce_conditional_statement<CS: ConstraintSystem<F>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: &str,
|
|
||||||
function_scope: &str,
|
|
||||||
indicator: &Boolean,
|
indicator: &Boolean,
|
||||||
return_type: Option<Type>,
|
statement: &ConditionalStatement,
|
||||||
declared_circuit_reference: &str,
|
|
||||||
mut_self: bool,
|
|
||||||
statement: ConditionalStatement,
|
|
||||||
) -> StatementResult<Vec<IndicatorAndConstrainedValue<F, G>>> {
|
) -> StatementResult<Vec<IndicatorAndConstrainedValue<F, G>>> {
|
||||||
let statement_string = statement.to_string();
|
let span = statement.span.clone().unwrap_or_default();
|
||||||
|
|
||||||
// Inherit an indicator from a previous statement.
|
// Inherit an indicator from a previous statement.
|
||||||
let outer_indicator = indicator;
|
let outer_indicator = indicator;
|
||||||
|
|
||||||
// Evaluate the conditional boolean as the inner indicator
|
// Evaluate the conditional boolean as the inner indicator
|
||||||
let inner_indicator = match self.enforce_expression(
|
let inner_indicator = match self.enforce_expression(cs, &statement.condition)? {
|
||||||
cs,
|
|
||||||
file_scope,
|
|
||||||
function_scope,
|
|
||||||
Some(Type::Boolean),
|
|
||||||
statement.condition.clone(),
|
|
||||||
)? {
|
|
||||||
ConstrainedValue::Boolean(resolved) => resolved,
|
ConstrainedValue::Boolean(resolved) => resolved,
|
||||||
value => {
|
value => {
|
||||||
return Err(StatementError::conditional_boolean(
|
return Err(StatementError::conditional_boolean(value.to_string(), span));
|
||||||
value.to_string(),
|
|
||||||
statement.span.clone(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -85,30 +70,16 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
outer_indicator_string, inner_indicator_string
|
outer_indicator_string, inner_indicator_string
|
||||||
);
|
);
|
||||||
let branch_1_indicator = Boolean::and(
|
let branch_1_indicator = Boolean::and(
|
||||||
&mut cs.ns(|| {
|
&mut cs.ns(|| format!("branch 1 {} {}:{}", span.text, &span.line, &span.start)),
|
||||||
format!(
|
|
||||||
"branch 1 {} {}:{}",
|
|
||||||
statement_string, &statement.span.line, &statement.span.start
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
outer_indicator,
|
outer_indicator,
|
||||||
&inner_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![];
|
let mut results = vec![];
|
||||||
|
|
||||||
// Evaluate branch 1
|
// Evaluate branch 1
|
||||||
let mut branch_1_result = self.evaluate_block(
|
let mut branch_1_result = self.enforce_statement(cs, &branch_1_indicator, &statement.result)?;
|
||||||
cs,
|
|
||||||
file_scope,
|
|
||||||
function_scope,
|
|
||||||
&branch_1_indicator,
|
|
||||||
statement.block,
|
|
||||||
return_type.clone(),
|
|
||||||
declared_circuit_reference,
|
|
||||||
mut_self,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
results.append(&mut branch_1_result);
|
results.append(&mut branch_1_result);
|
||||||
|
|
||||||
@ -119,26 +90,16 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
"branch indicator 2 {} && {}",
|
"branch indicator 2 {} && {}",
|
||||||
outer_indicator_string, inner_indicator_string
|
outer_indicator_string, inner_indicator_string
|
||||||
);
|
);
|
||||||
let span = statement.span.clone();
|
|
||||||
let branch_2_indicator = Boolean::and(
|
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,
|
&outer_indicator,
|
||||||
&inner_indicator,
|
&inner_indicator,
|
||||||
)
|
)
|
||||||
.map_err(|_| StatementError::indicator_calculation(branch_2_name, span.clone()))?;
|
.map_err(|_| StatementError::indicator_calculation(branch_2_name, span.clone()))?;
|
||||||
|
|
||||||
// Evaluate branch 2
|
// Evaluate branch 2
|
||||||
let mut branch_2_result = match statement.next {
|
let mut branch_2_result = match &statement.next {
|
||||||
Some(next) => self.enforce_statement(
|
Some(next) => self.enforce_statement(cs, &branch_2_indicator, next)?,
|
||||||
cs,
|
|
||||||
file_scope,
|
|
||||||
function_scope,
|
|
||||||
&branch_2_indicator,
|
|
||||||
*next,
|
|
||||||
return_type,
|
|
||||||
declared_circuit_reference,
|
|
||||||
mut_self,
|
|
||||||
)?,
|
|
||||||
None => vec![],
|
None => vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
//! Enforces a definition statement in a compiled Leo program.
|
//! Enforces a definition statement in a compiled Leo program.
|
||||||
|
|
||||||
use crate::{errors::StatementError, program::ConstrainedProgram, ConstrainedValue, GroupType};
|
use crate::{errors::StatementError, program::ConstrainedProgram, ConstrainedValue, GroupType};
|
||||||
use leo_ast::{Declare, DefinitionStatement, Span, VariableName};
|
use leo_asg::{DefinitionStatement, Span, Variable};
|
||||||
|
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
@ -25,35 +25,9 @@ use snarkvm_models::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||||
fn enforce_single_definition<CS: ConstraintSystem<F>>(
|
fn enforce_multiple_definition(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
variable_names: &[Variable],
|
||||||
function_scope: &str,
|
|
||||||
is_constant: bool,
|
|
||||||
variable_name: VariableName,
|
|
||||||
mut value: ConstrainedValue<F, G>,
|
|
||||||
span: &Span,
|
|
||||||
) -> Result<(), StatementError> {
|
|
||||||
if is_constant && variable_name.mutable {
|
|
||||||
return Err(StatementError::immutable_assign(
|
|
||||||
variable_name.to_string(),
|
|
||||||
span.to_owned(),
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
value.allocate_value(cs, span)?
|
|
||||||
}
|
|
||||||
|
|
||||||
self.store_definition(function_scope, variable_name.mutable, variable_name.identifier, value);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn enforce_multiple_definition<CS: ConstraintSystem<F>>(
|
|
||||||
&mut self,
|
|
||||||
cs: &mut CS,
|
|
||||||
function_scope: &str,
|
|
||||||
is_constant: bool,
|
|
||||||
variable_names: Vec<VariableName>,
|
|
||||||
values: Vec<ConstrainedValue<F, G>>,
|
values: Vec<ConstrainedValue<F, G>>,
|
||||||
span: &Span,
|
span: &Span,
|
||||||
) -> Result<(), StatementError> {
|
) -> Result<(), StatementError> {
|
||||||
@ -65,8 +39,8 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (variable, value) in variable_names.into_iter().zip(values.into_iter()) {
|
for (variable, value) in variable_names.iter().zip(values.into_iter()) {
|
||||||
self.enforce_single_definition(cs, function_scope, is_constant, variable, value, span)?;
|
self.store_definition(variable, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -76,39 +50,25 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
pub fn enforce_definition_statement<CS: ConstraintSystem<F>>(
|
pub fn enforce_definition_statement<CS: ConstraintSystem<F>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: &str,
|
statement: &DefinitionStatement,
|
||||||
function_scope: &str,
|
|
||||||
statement: DefinitionStatement,
|
|
||||||
) -> Result<(), StatementError> {
|
) -> Result<(), StatementError> {
|
||||||
let num_variables = statement.variable_names.len();
|
let num_variables = statement.variables.len();
|
||||||
let is_constant = match statement.declaration_type {
|
let expression = self.enforce_expression(cs, &statement.value)?;
|
||||||
Declare::Let => false,
|
|
||||||
Declare::Const => true,
|
|
||||||
};
|
|
||||||
let expression =
|
|
||||||
self.enforce_expression(cs, file_scope, function_scope, statement.type_.clone(), statement.value)?;
|
|
||||||
|
|
||||||
|
let span = statement.span.clone().unwrap_or_default();
|
||||||
if num_variables == 1 {
|
if num_variables == 1 {
|
||||||
// Define a single variable with a single value
|
// Define a single variable with a single value
|
||||||
let variable = statement.variable_names[0].clone();
|
self.store_definition(statement.variables.get(0).unwrap(), expression);
|
||||||
|
Ok(())
|
||||||
self.enforce_single_definition(cs, function_scope, is_constant, variable, expression, &statement.span)
|
|
||||||
} else {
|
} else {
|
||||||
// Define multiple variables for an expression that returns multiple results (multiple definition)
|
// Define multiple variables for an expression that returns multiple results (multiple definition)
|
||||||
let values = match expression {
|
let values = match expression {
|
||||||
// ConstrainedValue::Return(values) => values,
|
// ConstrainedValue::Return(values) => values,
|
||||||
ConstrainedValue::Tuple(values) => values,
|
ConstrainedValue::Tuple(values) => values,
|
||||||
value => return Err(StatementError::multiple_definition(value.to_string(), statement.span)),
|
value => return Err(StatementError::multiple_definition(value.to_string(), span)),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.enforce_multiple_definition(
|
self.enforce_multiple_definition(&statement.variables, values, &span)
|
||||||
cs,
|
|
||||||
function_scope,
|
|
||||||
is_constant,
|
|
||||||
statement.variable_names,
|
|
||||||
values,
|
|
||||||
&statement.span,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
//! Enforces an iteration statement in a compiled Leo program.
|
//! Enforces an iteration statement in a compiled Leo program.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
new_scope,
|
|
||||||
program::ConstrainedProgram,
|
program::ConstrainedProgram,
|
||||||
value::ConstrainedValue,
|
value::ConstrainedValue,
|
||||||
GroupType,
|
GroupType,
|
||||||
@ -25,7 +24,7 @@ use crate::{
|
|||||||
Integer,
|
Integer,
|
||||||
StatementResult,
|
StatementResult,
|
||||||
};
|
};
|
||||||
use leo_ast::{IterationStatement, Type};
|
use leo_asg::IterationStatement;
|
||||||
|
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
@ -40,41 +39,32 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
pub fn enforce_iteration_statement<CS: ConstraintSystem<F>>(
|
pub fn enforce_iteration_statement<CS: ConstraintSystem<F>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: &str,
|
|
||||||
function_scope: &str,
|
|
||||||
indicator: &Boolean,
|
indicator: &Boolean,
|
||||||
return_type: Option<Type>,
|
statement: &IterationStatement,
|
||||||
declared_circuit_reference: &str,
|
|
||||||
mut_self: bool,
|
|
||||||
statement: IterationStatement,
|
|
||||||
) -> StatementResult<Vec<IndicatorAndConstrainedValue<F, G>>> {
|
) -> StatementResult<Vec<IndicatorAndConstrainedValue<F, G>>> {
|
||||||
let mut results = vec![];
|
let mut results = vec![];
|
||||||
|
|
||||||
let from = self.enforce_index(cs, file_scope, function_scope, statement.start, &statement.span)?;
|
let span = statement.span.clone().unwrap_or_default();
|
||||||
let to = self.enforce_index(cs, file_scope, function_scope, statement.stop, &statement.span)?;
|
|
||||||
|
let from = self.enforce_index(cs, &statement.start, &span)?;
|
||||||
|
let to = self.enforce_index(cs, &statement.stop, &span)?;
|
||||||
|
|
||||||
let span = statement.span.clone();
|
|
||||||
for i in from..to {
|
for i in from..to {
|
||||||
// Store index in current function scope.
|
// Store index in current function scope.
|
||||||
// For loop scope is not implemented.
|
// 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(
|
self.store(
|
||||||
index_name,
|
variable.id,
|
||||||
ConstrainedValue::Integer(Integer::U32(UInt32::constant(i as u32))),
|
ConstrainedValue::Integer(Integer::U32(UInt32::constant(i as u32))),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Evaluate statements and possibly return early
|
// 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)),
|
&mut cs.ns(|| format!("for loop iteration {} {}:{}", i, &span.line, &span.start)),
|
||||||
file_scope,
|
|
||||||
function_scope,
|
|
||||||
indicator,
|
indicator,
|
||||||
statement.block.clone(),
|
&statement.body,
|
||||||
return_type.clone(),
|
|
||||||
declared_circuit_reference,
|
|
||||||
mut_self,
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
results.extend(result);
|
results.extend(result);
|
||||||
|
@ -17,49 +17,20 @@
|
|||||||
//! Enforces a return statement in a compiled Leo program.
|
//! Enforces a return statement in a compiled Leo program.
|
||||||
|
|
||||||
use crate::{errors::StatementError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
use crate::{errors::StatementError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
||||||
use leo_ast::{ReturnStatement, Span, Type};
|
use leo_asg::ReturnStatement;
|
||||||
|
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
gadgets::r1cs::ConstraintSystem,
|
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<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||||
pub fn enforce_return_statement<CS: ConstraintSystem<F>>(
|
pub fn enforce_return_statement<CS: ConstraintSystem<F>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: &str,
|
statement: &ReturnStatement,
|
||||||
function_scope: &str,
|
|
||||||
return_type: Option<Type>,
|
|
||||||
statement: ReturnStatement,
|
|
||||||
) -> Result<ConstrainedValue<F, G>, StatementError> {
|
) -> Result<ConstrainedValue<F, G>, StatementError> {
|
||||||
let result = self.enforce_operand(
|
let result = self.enforce_operand(cs, &statement.expression)?;
|
||||||
cs,
|
|
||||||
file_scope,
|
|
||||||
function_scope,
|
|
||||||
return_type.clone(),
|
|
||||||
statement.expression,
|
|
||||||
&statement.span,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// Make sure we return the correct type.
|
|
||||||
if let Some(expected) = return_type {
|
|
||||||
check_return_type(&expected, &result.to_type(&statement.span)?, &statement.span)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,8 @@
|
|||||||
//! Enforces a statement in a compiled Leo program.
|
//! Enforces a statement in a compiled Leo program.
|
||||||
|
|
||||||
use crate::{errors::StatementError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
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::{
|
use snarkvm_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
@ -39,73 +40,38 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
pub fn enforce_statement<CS: ConstraintSystem<F>>(
|
pub fn enforce_statement<CS: ConstraintSystem<F>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: &str,
|
|
||||||
function_scope: &str,
|
|
||||||
indicator: &Boolean,
|
indicator: &Boolean,
|
||||||
statement: Statement,
|
statement: &Arc<Statement>,
|
||||||
return_type: Option<Type>,
|
|
||||||
declared_circuit_reference: &str,
|
|
||||||
mut_self: bool,
|
|
||||||
) -> StatementResult<Vec<IndicatorAndConstrainedValue<F, G>>> {
|
) -> StatementResult<Vec<IndicatorAndConstrainedValue<F, G>>> {
|
||||||
let mut results = vec![];
|
let mut results = vec![];
|
||||||
|
|
||||||
match statement {
|
match &**statement {
|
||||||
Statement::Return(statement) => {
|
Statement::Return(statement) => {
|
||||||
let return_value = (
|
let return_value = (*indicator, self.enforce_return_statement(cs, statement)?);
|
||||||
*indicator,
|
|
||||||
self.enforce_return_statement(cs, file_scope, function_scope, return_type, statement)?,
|
|
||||||
);
|
|
||||||
|
|
||||||
results.push(return_value);
|
results.push(return_value);
|
||||||
}
|
}
|
||||||
Statement::Definition(statement) => {
|
Statement::Definition(statement) => {
|
||||||
self.enforce_definition_statement(cs, file_scope, function_scope, statement)?;
|
self.enforce_definition_statement(cs, statement)?;
|
||||||
}
|
}
|
||||||
Statement::Assign(statement) => {
|
Statement::Assign(statement) => {
|
||||||
self.enforce_assign_statement(
|
self.enforce_assign_statement(cs, indicator, statement)?;
|
||||||
cs,
|
|
||||||
file_scope,
|
|
||||||
function_scope,
|
|
||||||
declared_circuit_reference,
|
|
||||||
indicator,
|
|
||||||
mut_self,
|
|
||||||
statement,
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
Statement::Conditional(statement) => {
|
Statement::Conditional(statement) => {
|
||||||
let result = self.enforce_conditional_statement(
|
let result = self.enforce_conditional_statement(cs, indicator, statement)?;
|
||||||
cs,
|
|
||||||
file_scope,
|
|
||||||
function_scope,
|
|
||||||
indicator,
|
|
||||||
return_type,
|
|
||||||
declared_circuit_reference,
|
|
||||||
mut_self,
|
|
||||||
statement,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
results.extend(result);
|
results.extend(result);
|
||||||
}
|
}
|
||||||
Statement::Iteration(statement) => {
|
Statement::Iteration(statement) => {
|
||||||
let result = self.enforce_iteration_statement(
|
let result = self.enforce_iteration_statement(cs, indicator, statement)?;
|
||||||
cs,
|
|
||||||
file_scope,
|
|
||||||
function_scope,
|
|
||||||
indicator,
|
|
||||||
return_type,
|
|
||||||
declared_circuit_reference,
|
|
||||||
mut_self,
|
|
||||||
statement,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
results.extend(result);
|
results.extend(result);
|
||||||
}
|
}
|
||||||
Statement::Console(statement) => {
|
Statement::Console(statement) => {
|
||||||
self.evaluate_console_function_call(cs, file_scope, function_scope, indicator, statement)?;
|
self.evaluate_console_function_call(cs, indicator, statement)?;
|
||||||
}
|
}
|
||||||
Statement::Expression(statement) => {
|
Statement::Expression(statement) => {
|
||||||
let expression_string = statement.expression.to_string();
|
let value = self.enforce_expression(cs, &statement.expression)?;
|
||||||
let value = self.enforce_expression(cs, file_scope, function_scope, None, statement.expression)?;
|
|
||||||
// handle empty return value cases
|
// handle empty return value cases
|
||||||
match &value {
|
match &value {
|
||||||
ConstrainedValue::Tuple(values) => {
|
ConstrainedValue::Tuple(values) => {
|
||||||
@ -113,20 +79,20 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
results.push((*indicator, value));
|
results.push((*indicator, value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => return Err(StatementError::unassigned(expression_string, statement.span)),
|
_ => {
|
||||||
|
return Err(StatementError::unassigned(
|
||||||
|
statement.span.as_ref().map(|x| x.text.clone()).unwrap_or_default(),
|
||||||
|
statement.span.clone().unwrap_or_default(),
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Statement::Block(statement) => {
|
Statement::Block(statement) => {
|
||||||
let span = statement.span.clone();
|
let span = statement.span.clone().unwrap_or_default();
|
||||||
let result = self.evaluate_block(
|
let result = self.evaluate_block(
|
||||||
&mut cs.ns(|| format!("block {}:{}", &span.line, &span.start)),
|
&mut cs.ns(|| format!("block {}:{}", &span.line, &span.start)),
|
||||||
file_scope,
|
|
||||||
function_scope,
|
|
||||||
indicator,
|
indicator,
|
||||||
statement,
|
statement,
|
||||||
return_type,
|
|
||||||
declared_circuit_reference,
|
|
||||||
mut_self,
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
results.extend(result);
|
results.extend(result);
|
||||||
|
@ -28,14 +28,6 @@ use snarkvm_models::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) fn new_bool_constant(string: String, span: &Span) -> Result<Boolean, BooleanError> {
|
|
||||||
let boolean = string
|
|
||||||
.parse::<bool>()
|
|
||||||
.map_err(|_| BooleanError::invalid_boolean(string, span.to_owned()))?;
|
|
||||||
|
|
||||||
Ok(Boolean::constant(boolean))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn allocate_bool<F: Field + PrimeField, CS: ConstraintSystem<F>>(
|
pub(crate) fn allocate_bool<F: Field + PrimeField, CS: ConstraintSystem<F>>(
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
name: &str,
|
name: &str,
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
//! A data type that represents members in the group formed by the set of affine points on a curve.
|
//! A data type that represents members in the group formed by the set of affine points on a curve.
|
||||||
|
|
||||||
use crate::errors::GroupError;
|
use crate::errors::GroupError;
|
||||||
use leo_ast::{GroupValue, Span};
|
use leo_asg::{GroupValue, Span};
|
||||||
|
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
curves::{Field, One},
|
curves::{Field, One},
|
||||||
@ -48,7 +48,7 @@ pub trait GroupType<F: Field>:
|
|||||||
+ ToBitsGadget<F>
|
+ ToBitsGadget<F>
|
||||||
+ ToBytesGadget<F>
|
+ ToBytesGadget<F>
|
||||||
{
|
{
|
||||||
fn constant(value: GroupValue) -> Result<Self, GroupError>;
|
fn constant(value: &GroupValue, span: &Span) -> Result<Self, GroupError>;
|
||||||
|
|
||||||
fn to_allocated<CS: ConstraintSystem<F>>(&self, cs: CS, span: &Span) -> Result<Self, GroupError>;
|
fn to_allocated<CS: ConstraintSystem<F>>(&self, cs: CS, span: &Span) -> Result<Self, GroupError>;
|
||||||
|
|
||||||
|
@ -17,7 +17,8 @@
|
|||||||
//! Methods to enforce constraints on input group values in a Leo program.
|
//! Methods to enforce constraints on input group values in a Leo program.
|
||||||
|
|
||||||
use crate::{errors::GroupError, ConstrainedValue, GroupType};
|
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_errors::gadgets::SynthesisError;
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
@ -56,7 +57,15 @@ pub(crate) fn group_from_input<F: Field + PrimeField, G: GroupType<F>, CS: Const
|
|||||||
None => None,
|
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))
|
Ok(ConstrainedValue::Group(group))
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{errors::GroupError, GroupType};
|
use crate::{errors::GroupError, GroupType};
|
||||||
use leo_ast::{GroupCoordinate, GroupTuple, GroupValue, Span};
|
use leo_asg::{GroupCoordinate, GroupValue, Span};
|
||||||
|
|
||||||
use snarkvm_curves::{
|
use snarkvm_curves::{
|
||||||
edwards_bls12::{EdwardsAffine, EdwardsParameters, Fq},
|
edwards_bls12::{EdwardsAffine, EdwardsParameters, Fq},
|
||||||
@ -52,8 +52,8 @@ pub enum EdwardsGroupType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl GroupType<Fq> for EdwardsGroupType {
|
impl GroupType<Fq> for EdwardsGroupType {
|
||||||
fn constant(group: GroupValue) -> Result<Self, GroupError> {
|
fn constant(group: &GroupValue, span: &Span) -> Result<Self, GroupError> {
|
||||||
let value = Self::edwards_affine_from_value(group)?;
|
let value = Self::edwards_affine_from_value(group, span)?;
|
||||||
|
|
||||||
Ok(EdwardsGroupType::Constant(value))
|
Ok(EdwardsGroupType::Constant(value))
|
||||||
}
|
}
|
||||||
@ -134,75 +134,79 @@ impl GroupType<Fq> for EdwardsGroupType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl EdwardsGroupType {
|
impl EdwardsGroupType {
|
||||||
pub fn edwards_affine_from_value(value: GroupValue) -> Result<EdwardsAffine, GroupError> {
|
pub fn edwards_affine_from_value(value: &GroupValue, span: &Span) -> Result<EdwardsAffine, GroupError> {
|
||||||
match value {
|
match value {
|
||||||
GroupValue::Single(number, span) => Self::edwards_affine_from_single(number, span),
|
GroupValue::Single(number, ..) => Self::edwards_affine_from_single(number, span),
|
||||||
GroupValue::Tuple(tuple) => Self::edwards_affine_from_tuple(tuple),
|
GroupValue::Tuple(x, y) => Self::edwards_affine_from_tuple(x, y, span),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn edwards_affine_from_single(number: String, span: Span) -> Result<EdwardsAffine, GroupError> {
|
pub fn edwards_affine_from_single(number: &str, span: &Span) -> Result<EdwardsAffine, GroupError> {
|
||||||
if number.eq("0") {
|
if number.eq("0") {
|
||||||
Ok(EdwardsAffine::zero())
|
Ok(EdwardsAffine::zero())
|
||||||
} else {
|
} else {
|
||||||
let one = edwards_affine_one();
|
let one = edwards_affine_one();
|
||||||
let number_value = Fp256::from_str(&number).map_err(|_| GroupError::n_group(number, span))?;
|
let number_value =
|
||||||
|
Fp256::from_str(&number).map_err(|_| GroupError::n_group(number.to_string(), span.clone()))?;
|
||||||
let result: EdwardsAffine = one.mul(&number_value);
|
let result: EdwardsAffine = one.mul(&number_value);
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn edwards_affine_from_tuple(group: GroupTuple) -> Result<EdwardsAffine, GroupError> {
|
pub fn edwards_affine_from_tuple(
|
||||||
let span = group.span;
|
x: &GroupCoordinate,
|
||||||
let x = group.x;
|
y: &GroupCoordinate,
|
||||||
let y = group.y;
|
span: &Span,
|
||||||
|
) -> Result<EdwardsAffine, GroupError> {
|
||||||
|
let x = x.clone();
|
||||||
|
let y = y.clone();
|
||||||
|
|
||||||
match (x, y) {
|
match (x, y) {
|
||||||
// (x, y)
|
// (x, y)
|
||||||
(GroupCoordinate::Number(x_string, x_span), GroupCoordinate::Number(y_string, y_span)) => {
|
(GroupCoordinate::Number(x_string), GroupCoordinate::Number(y_string)) => {
|
||||||
Self::edwards_affine_from_pair(x_string, y_string, x_span, y_span, span)
|
Self::edwards_affine_from_pair(x_string, y_string, span, span, span)
|
||||||
}
|
}
|
||||||
// (x, +)
|
// (x, +)
|
||||||
(GroupCoordinate::Number(x_string, x_span), GroupCoordinate::SignHigh) => {
|
(GroupCoordinate::Number(x_string), GroupCoordinate::SignHigh) => {
|
||||||
Self::edwards_affine_from_x_str(x_string, x_span, Some(true), span)
|
Self::edwards_affine_from_x_str(x_string, span, Some(true), span)
|
||||||
}
|
}
|
||||||
// (x, -)
|
// (x, -)
|
||||||
(GroupCoordinate::Number(x_string, x_span), GroupCoordinate::SignLow) => {
|
(GroupCoordinate::Number(x_string), GroupCoordinate::SignLow) => {
|
||||||
Self::edwards_affine_from_x_str(x_string, x_span, Some(false), span)
|
Self::edwards_affine_from_x_str(x_string, span, Some(false), span)
|
||||||
}
|
}
|
||||||
// (x, _)
|
// (x, _)
|
||||||
(GroupCoordinate::Number(x_string, x_span), GroupCoordinate::Inferred) => {
|
(GroupCoordinate::Number(x_string), GroupCoordinate::Inferred) => {
|
||||||
Self::edwards_affine_from_x_str(x_string, x_span, None, span)
|
Self::edwards_affine_from_x_str(x_string, span, None, span)
|
||||||
}
|
}
|
||||||
// (+, y)
|
// (+, y)
|
||||||
(GroupCoordinate::SignHigh, GroupCoordinate::Number(y_string, y_span)) => {
|
(GroupCoordinate::SignHigh, GroupCoordinate::Number(y_string)) => {
|
||||||
Self::edwards_affine_from_y_str(y_string, y_span, Some(true), span)
|
Self::edwards_affine_from_y_str(y_string, span, Some(true), span)
|
||||||
}
|
}
|
||||||
// (-, y)
|
// (-, y)
|
||||||
(GroupCoordinate::SignLow, GroupCoordinate::Number(y_string, y_span)) => {
|
(GroupCoordinate::SignLow, GroupCoordinate::Number(y_string)) => {
|
||||||
Self::edwards_affine_from_y_str(y_string, y_span, Some(false), span)
|
Self::edwards_affine_from_y_str(y_string, span, Some(false), span)
|
||||||
}
|
}
|
||||||
// (_, y)
|
// (_, y)
|
||||||
(GroupCoordinate::Inferred, GroupCoordinate::Number(y_string, y_span)) => {
|
(GroupCoordinate::Inferred, GroupCoordinate::Number(y_string)) => {
|
||||||
Self::edwards_affine_from_y_str(y_string, y_span, None, span)
|
Self::edwards_affine_from_y_str(y_string, span, None, span)
|
||||||
}
|
}
|
||||||
// Invalid
|
// Invalid
|
||||||
(x, y) => Err(GroupError::invalid_group(format!("({}, {})", x, y), span)),
|
(x, y) => Err(GroupError::invalid_group(format!("({}, {})", x, y), span.clone())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn edwards_affine_from_x_str(
|
pub fn edwards_affine_from_x_str(
|
||||||
x_string: String,
|
x_string: String,
|
||||||
x_span: Span,
|
x_span: &Span,
|
||||||
greatest: Option<bool>,
|
greatest: Option<bool>,
|
||||||
element_span: Span,
|
element_span: &Span,
|
||||||
) -> Result<EdwardsAffine, GroupError> {
|
) -> Result<EdwardsAffine, GroupError> {
|
||||||
let x = Fq::from_str(&x_string).map_err(|_| GroupError::x_invalid(x_string, x_span))?;
|
let x = Fq::from_str(&x_string).map_err(|_| GroupError::x_invalid(x_string, x_span.clone()))?;
|
||||||
match greatest {
|
match greatest {
|
||||||
// Sign provided
|
// Sign provided
|
||||||
Some(greatest) => {
|
Some(greatest) => {
|
||||||
EdwardsAffine::from_x_coordinate(x, greatest).ok_or_else(|| GroupError::x_recover(element_span))
|
EdwardsAffine::from_x_coordinate(x, greatest).ok_or_else(|| GroupError::x_recover(element_span.clone()))
|
||||||
}
|
}
|
||||||
// Sign inferred
|
// Sign inferred
|
||||||
None => {
|
None => {
|
||||||
@ -217,23 +221,23 @@ impl EdwardsGroupType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise return error.
|
// Otherwise return error.
|
||||||
Err(GroupError::x_recover(element_span))
|
Err(GroupError::x_recover(element_span.clone()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn edwards_affine_from_y_str(
|
pub fn edwards_affine_from_y_str(
|
||||||
y_string: String,
|
y_string: String,
|
||||||
y_span: Span,
|
y_span: &Span,
|
||||||
greatest: Option<bool>,
|
greatest: Option<bool>,
|
||||||
element_span: Span,
|
element_span: &Span,
|
||||||
) -> Result<EdwardsAffine, GroupError> {
|
) -> Result<EdwardsAffine, GroupError> {
|
||||||
let y = Fq::from_str(&y_string).map_err(|_| GroupError::y_invalid(y_string, y_span))?;
|
let y = Fq::from_str(&y_string).map_err(|_| GroupError::y_invalid(y_string, y_span.clone()))?;
|
||||||
|
|
||||||
match greatest {
|
match greatest {
|
||||||
// Sign provided
|
// Sign provided
|
||||||
Some(greatest) => {
|
Some(greatest) => {
|
||||||
EdwardsAffine::from_y_coordinate(y, greatest).ok_or_else(|| GroupError::y_recover(element_span))
|
EdwardsAffine::from_y_coordinate(y, greatest).ok_or_else(|| GroupError::y_recover(element_span.clone()))
|
||||||
}
|
}
|
||||||
// Sign inferred
|
// Sign inferred
|
||||||
None => {
|
None => {
|
||||||
@ -248,7 +252,7 @@ impl EdwardsGroupType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise return error.
|
// Otherwise return error.
|
||||||
Err(GroupError::y_recover(element_span))
|
Err(GroupError::y_recover(element_span.clone()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -256,19 +260,19 @@ impl EdwardsGroupType {
|
|||||||
pub fn edwards_affine_from_pair(
|
pub fn edwards_affine_from_pair(
|
||||||
x_string: String,
|
x_string: String,
|
||||||
y_string: String,
|
y_string: String,
|
||||||
x_span: Span,
|
x_span: &Span,
|
||||||
y_span: Span,
|
y_span: &Span,
|
||||||
element_span: Span,
|
element_span: &Span,
|
||||||
) -> Result<EdwardsAffine, GroupError> {
|
) -> Result<EdwardsAffine, GroupError> {
|
||||||
let x = Fq::from_str(&x_string).map_err(|_| GroupError::x_invalid(x_string, x_span))?;
|
let x = Fq::from_str(&x_string).map_err(|_| GroupError::x_invalid(x_string, x_span.clone()))?;
|
||||||
let y = Fq::from_str(&y_string).map_err(|_| GroupError::y_invalid(y_string, y_span))?;
|
let y = Fq::from_str(&y_string).map_err(|_| GroupError::y_invalid(y_string, y_span.clone()))?;
|
||||||
|
|
||||||
let element = EdwardsAffine::new(x, y);
|
let element = EdwardsAffine::new(x, y);
|
||||||
|
|
||||||
if element.is_on_curve() {
|
if element.is_on_curve() {
|
||||||
Ok(element)
|
Ok(element)
|
||||||
} else {
|
} else {
|
||||||
Err(GroupError::not_on_curve(element.to_string(), element_span))
|
Err(GroupError::not_on_curve(element.to_string(), element_span.clone()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,7 +287,7 @@ impl EdwardsGroupType {
|
|||||||
_ => Err(SynthesisError::AssignmentMissing),
|
_ => 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<CS: ConstraintSystem<Fq>>(&self, mut cs: CS) -> Result<EdwardsBlsGadget, SynthesisError> {
|
pub fn allocated<CS: ConstraintSystem<Fq>>(&self, mut cs: CS) -> Result<EdwardsBlsGadget, SynthesisError> {
|
||||||
|
@ -1,33 +0,0 @@
|
|||||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
|
||||||
// This file is part of the Leo library.
|
|
||||||
|
|
||||||
// The Leo library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// The Leo library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
//! Enforces constraints on an implicit number in a compiled Leo program.
|
|
||||||
|
|
||||||
use crate::{errors::ValueError, value::ConstrainedValue, GroupType};
|
|
||||||
use leo_ast::{Span, Type};
|
|
||||||
|
|
||||||
use snarkvm_models::curves::{Field, PrimeField};
|
|
||||||
|
|
||||||
pub fn enforce_number_implicit<F: Field + PrimeField, G: GroupType<F>>(
|
|
||||||
expected_type: Option<Type>,
|
|
||||||
value: String,
|
|
||||||
span: &Span,
|
|
||||||
) -> Result<ConstrainedValue<F, G>, ValueError> {
|
|
||||||
match expected_type {
|
|
||||||
Some(type_) => Ok(ConstrainedValue::from_type(value, &type_, span)?),
|
|
||||||
None => Ok(ConstrainedValue::Unresolved(value)),
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
|
||||||
// This file is part of the Leo library.
|
|
||||||
|
|
||||||
// The Leo library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// The Leo library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
pub mod implicit;
|
|
||||||
pub use self::implicit::*;
|
|
@ -16,7 +16,8 @@
|
|||||||
|
|
||||||
//! Conversion of integer declarations to constraints in Leo.
|
//! Conversion of integer declarations to constraints in Leo.
|
||||||
use crate::{errors::IntegerError, IntegerTrait};
|
use crate::{errors::IntegerError, IntegerTrait};
|
||||||
use leo_ast::{InputValue, IntegerType, Span, Type};
|
use leo_asg::{ConstInt, IntegerType, Span};
|
||||||
|
use leo_ast::InputValue;
|
||||||
use leo_gadgets::{
|
use leo_gadgets::{
|
||||||
arithmetic::*,
|
arithmetic::*,
|
||||||
bits::comparator::{ComparatorGadget, EvaluateLtGadget},
|
bits::comparator::{ComparatorGadget, EvaluateLtGadget},
|
||||||
@ -72,112 +73,18 @@ impl Integer {
|
|||||||
///
|
///
|
||||||
/// Checks that the expression is equal to the expected type if given.
|
/// Checks that the expression is equal to the expected type if given.
|
||||||
///
|
///
|
||||||
pub fn new(
|
pub fn new(value: &ConstInt) -> Self {
|
||||||
expected_type: Option<Type>,
|
match value {
|
||||||
actual_integer_type: &IntegerType,
|
ConstInt::U8(i) => Integer::U8(UInt8::constant(*i)),
|
||||||
string: String,
|
ConstInt::U16(i) => Integer::U16(UInt16::constant(*i)),
|
||||||
span: &Span,
|
ConstInt::U32(i) => Integer::U32(UInt32::constant(*i)),
|
||||||
) -> Result<Self, IntegerError> {
|
ConstInt::U64(i) => Integer::U64(UInt64::constant(*i)),
|
||||||
// Check expected type if given.
|
ConstInt::U128(i) => Integer::U128(UInt128::constant(*i)),
|
||||||
if let Some(type_) = expected_type {
|
ConstInt::I8(i) => Integer::I8(Int8::constant(*i)),
|
||||||
// Check expected type is an integer.
|
ConstInt::I16(i) => Integer::I16(Int16::constant(*i)),
|
||||||
match type_ {
|
ConstInt::I32(i) => Integer::I32(Int32::constant(*i)),
|
||||||
Type::IntegerType(expected_integer_type) => {
|
ConstInt::I64(i) => Integer::I64(Int64::constant(*i)),
|
||||||
// Check expected integer type == actual integer type
|
ConstInt::I128(i) => Integer::I128(Int128::constant(*i)),
|
||||||
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<Self, IntegerError> {
|
|
||||||
match integer_type {
|
|
||||||
IntegerType::U8 => {
|
|
||||||
let number = string
|
|
||||||
.parse::<u8>()
|
|
||||||
.map_err(|_| IntegerError::invalid_integer(string, span.to_owned()))?;
|
|
||||||
|
|
||||||
Ok(Integer::U8(UInt8::constant(number)))
|
|
||||||
}
|
|
||||||
IntegerType::U16 => {
|
|
||||||
let number = string
|
|
||||||
.parse::<u16>()
|
|
||||||
.map_err(|_| IntegerError::invalid_integer(string, span.to_owned()))?;
|
|
||||||
|
|
||||||
Ok(Integer::U16(UInt16::constant(number)))
|
|
||||||
}
|
|
||||||
IntegerType::U32 => {
|
|
||||||
let number = string
|
|
||||||
.parse::<u32>()
|
|
||||||
.map_err(|_| IntegerError::invalid_integer(string, span.to_owned()))?;
|
|
||||||
|
|
||||||
Ok(Integer::U32(UInt32::constant(number)))
|
|
||||||
}
|
|
||||||
IntegerType::U64 => {
|
|
||||||
let number = string
|
|
||||||
.parse::<u64>()
|
|
||||||
.map_err(|_| IntegerError::invalid_integer(string, span.to_owned()))?;
|
|
||||||
|
|
||||||
Ok(Integer::U64(UInt64::constant(number)))
|
|
||||||
}
|
|
||||||
IntegerType::U128 => {
|
|
||||||
let number = string
|
|
||||||
.parse::<u128>()
|
|
||||||
.map_err(|_| IntegerError::invalid_integer(string, span.to_owned()))?;
|
|
||||||
|
|
||||||
Ok(Integer::U128(UInt128::constant(number)))
|
|
||||||
}
|
|
||||||
|
|
||||||
IntegerType::I8 => {
|
|
||||||
let number = string
|
|
||||||
.parse::<i8>()
|
|
||||||
.map_err(|_| IntegerError::invalid_integer(string, span.to_owned()))?;
|
|
||||||
|
|
||||||
Ok(Integer::I8(Int8::constant(number)))
|
|
||||||
}
|
|
||||||
IntegerType::I16 => {
|
|
||||||
let number = string
|
|
||||||
.parse::<i16>()
|
|
||||||
.map_err(|_| IntegerError::invalid_integer(string, span.to_owned()))?;
|
|
||||||
|
|
||||||
Ok(Integer::I16(Int16::constant(number)))
|
|
||||||
}
|
|
||||||
IntegerType::I32 => {
|
|
||||||
let number = string
|
|
||||||
.parse::<i32>()
|
|
||||||
.map_err(|_| IntegerError::invalid_integer(string, span.to_owned()))?;
|
|
||||||
|
|
||||||
Ok(Integer::I32(Int32::constant(number)))
|
|
||||||
}
|
|
||||||
IntegerType::I64 => {
|
|
||||||
let number = string
|
|
||||||
.parse::<i64>()
|
|
||||||
.map_err(|_| IntegerError::invalid_integer(string, span.to_owned()))?;
|
|
||||||
|
|
||||||
Ok(Integer::I64(Int64::constant(number)))
|
|
||||||
}
|
|
||||||
IntegerType::I128 => {
|
|
||||||
let number = string
|
|
||||||
.parse::<i128>()
|
|
||||||
.map_err(|_| IntegerError::invalid_integer(string, span.to_owned()))?;
|
|
||||||
|
|
||||||
Ok(Integer::I128(Int128::constant(number)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,7 +127,7 @@ impl Integer {
|
|||||||
|
|
||||||
pub fn allocate_type<F: Field, CS: ConstraintSystem<F>>(
|
pub fn allocate_type<F: Field, CS: ConstraintSystem<F>>(
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
integer_type: IntegerType,
|
integer_type: &IntegerType,
|
||||||
name: &str,
|
name: &str,
|
||||||
option: Option<String>,
|
option: Option<String>,
|
||||||
span: &Span,
|
span: &Span,
|
||||||
@ -371,7 +278,7 @@ impl Integer {
|
|||||||
|
|
||||||
pub fn from_input<F: Field, CS: ConstraintSystem<F>>(
|
pub fn from_input<F: Field, CS: ConstraintSystem<F>>(
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
integer_type: IntegerType,
|
integer_type: &IntegerType,
|
||||||
name: &str,
|
name: &str,
|
||||||
integer_value: Option<InputValue>,
|
integer_value: Option<InputValue>,
|
||||||
span: &Span,
|
span: &Span,
|
||||||
|
@ -27,9 +27,6 @@ pub use self::field::*;
|
|||||||
pub mod group;
|
pub mod group;
|
||||||
pub use self::group::*;
|
pub use self::group::*;
|
||||||
|
|
||||||
pub mod implicit;
|
|
||||||
pub use self::implicit::*;
|
|
||||||
|
|
||||||
pub mod integer;
|
pub mod integer;
|
||||||
pub use self::integer::*;
|
pub use self::integer::*;
|
||||||
|
|
||||||
|
@ -16,18 +16,8 @@
|
|||||||
|
|
||||||
//! The in memory stored value for a defined name in a compiled Leo program.
|
//! The in memory stored value for a defined name in a compiled Leo program.
|
||||||
|
|
||||||
use crate::{
|
use crate::{errors::ValueError, Address, FieldType, GroupType, Integer};
|
||||||
boolean::input::{allocate_bool, new_bool_constant},
|
use leo_asg::{CircuitBody, Identifier, Span, Type};
|
||||||
errors::{ExpressionError, FieldError, ValueError},
|
|
||||||
is_in_scope,
|
|
||||||
new_scope,
|
|
||||||
Address,
|
|
||||||
FieldType,
|
|
||||||
GroupType,
|
|
||||||
Integer,
|
|
||||||
};
|
|
||||||
use leo_ast::{ArrayDimensions, Circuit, Function, GroupValue, Identifier, Span, Type};
|
|
||||||
use leo_core::Value;
|
|
||||||
|
|
||||||
use snarkvm_errors::gadgets::SynthesisError;
|
use snarkvm_errors::gadgets::SynthesisError;
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
@ -37,7 +27,7 @@ use snarkvm_models::{
|
|||||||
utilities::{boolean::Boolean, eq::ConditionalEqGadget, select::CondSelectGadget},
|
utilities::{boolean::Boolean, eq::ConditionalEqGadget, select::CondSelectGadget},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use std::fmt;
|
use std::{fmt, sync::Arc};
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
pub struct ConstrainedCircuitMember<F: Field + PrimeField, G: GroupType<F>>(pub Identifier, pub ConstrainedValue<F, G>);
|
pub struct ConstrainedCircuitMember<F: Field + PrimeField, G: GroupType<F>>(pub Identifier, pub ConstrainedValue<F, G>);
|
||||||
@ -58,50 +48,13 @@ pub enum ConstrainedValue<F: Field + PrimeField, G: GroupType<F>> {
|
|||||||
Tuple(Vec<ConstrainedValue<F, G>>),
|
Tuple(Vec<ConstrainedValue<F, G>>),
|
||||||
|
|
||||||
// Circuits
|
// Circuits
|
||||||
CircuitDefinition(Circuit),
|
CircuitExpression(Arc<CircuitBody>, Vec<ConstrainedCircuitMember<F, G>>),
|
||||||
CircuitExpression(Identifier, Vec<ConstrainedCircuitMember<F, G>>),
|
|
||||||
|
|
||||||
// Functions
|
|
||||||
Function(Option<Identifier>, Box<Function>), // (optional circuit identifier, function definition)
|
|
||||||
|
|
||||||
// Modifiers
|
// Modifiers
|
||||||
Mutable(Box<ConstrainedValue<F, G>>),
|
Mutable(Box<ConstrainedValue<F, G>>),
|
||||||
Static(Box<ConstrainedValue<F, G>>),
|
|
||||||
Unresolved(String),
|
|
||||||
|
|
||||||
// Imports
|
|
||||||
Import(String, Box<ConstrainedValue<F, G>>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
|
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
|
||||||
pub(crate) fn from_other(value: String, other: &ConstrainedValue<F, G>, span: &Span) -> Result<Self, ValueError> {
|
|
||||||
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<Self, ValueError> {
|
|
||||||
match type_ {
|
|
||||||
// Data types
|
|
||||||
Type::Address => Ok(ConstrainedValue::Address(Address::constant(value, span)?)),
|
|
||||||
Type::Boolean => Ok(ConstrainedValue::Boolean(new_bool_constant(value, span)?)),
|
|
||||||
Type::Field => Ok(ConstrainedValue::Field(FieldType::constant(value, span)?)),
|
|
||||||
Type::Group => Ok(ConstrainedValue::Group(G::constant(GroupValue::Single(
|
|
||||||
value,
|
|
||||||
span.to_owned(),
|
|
||||||
))?)),
|
|
||||||
Type::IntegerType(integer_type) => Ok(ConstrainedValue::Integer(Integer::new_constant(
|
|
||||||
integer_type,
|
|
||||||
value,
|
|
||||||
span,
|
|
||||||
)?)),
|
|
||||||
|
|
||||||
// Data type wrappers
|
|
||||||
Type::Array(ref type_, _dimensions) => ConstrainedValue::from_type(value, type_, span),
|
|
||||||
_ => Ok(ConstrainedValue::Unresolved(value)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn to_type(&self, span: &Span) -> Result<Type, ValueError> {
|
pub(crate) fn to_type(&self, span: &Span) -> Result<Type, ValueError> {
|
||||||
Ok(match self {
|
Ok(match self {
|
||||||
// Data types
|
// Data types
|
||||||
@ -109,21 +62,13 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
|
|||||||
ConstrainedValue::Boolean(_bool) => Type::Boolean,
|
ConstrainedValue::Boolean(_bool) => Type::Boolean,
|
||||||
ConstrainedValue::Field(_field) => Type::Field,
|
ConstrainedValue::Field(_field) => Type::Field,
|
||||||
ConstrainedValue::Group(_group) => Type::Group,
|
ConstrainedValue::Group(_group) => Type::Group,
|
||||||
ConstrainedValue::Integer(integer) => Type::IntegerType(integer.get_type()),
|
ConstrainedValue::Integer(integer) => Type::Integer(integer.get_type()),
|
||||||
|
|
||||||
// Data type wrappers
|
// Data type wrappers
|
||||||
ConstrainedValue::Array(array) => {
|
ConstrainedValue::Array(array) => {
|
||||||
let array_type = array[0].to_type(span)?;
|
let array_type = array[0].to_type(span)?;
|
||||||
let mut dimensions = ArrayDimensions::default();
|
|
||||||
dimensions.push_usize(array.len());
|
|
||||||
|
|
||||||
// Nested array type
|
Type::Array(Box::new(array_type), array.len())
|
||||||
if let Type::Array(inner_type, inner_dimensions) = &array_type {
|
|
||||||
dimensions.append(&mut inner_dimensions.clone());
|
|
||||||
return Ok(Type::Array(inner_type.clone(), dimensions));
|
|
||||||
}
|
|
||||||
|
|
||||||
Type::Array(Box::new(array_type), dimensions)
|
|
||||||
}
|
}
|
||||||
ConstrainedValue::Tuple(tuple) => {
|
ConstrainedValue::Tuple(tuple) => {
|
||||||
let mut types = Vec::with_capacity(tuple.len());
|
let mut types = Vec::with_capacity(tuple.len());
|
||||||
@ -135,100 +80,11 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
|
|||||||
|
|
||||||
Type::Tuple(types)
|
Type::Tuple(types)
|
||||||
}
|
}
|
||||||
ConstrainedValue::CircuitExpression(id, _members) => Type::Circuit(id.clone()),
|
ConstrainedValue::CircuitExpression(id, _members) => Type::Circuit(id.circuit.clone()),
|
||||||
ConstrainedValue::Mutable(value) => return value.to_type(span),
|
ConstrainedValue::Mutable(value) => return value.to_type(span),
|
||||||
value => return Err(ValueError::implicit(value.to_string(), span.to_owned())),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the `ConstrainedValue` in intermediate `Value` format (for core circuits)
|
|
||||||
pub(crate) fn to_value(&self) -> Value {
|
|
||||||
match self.clone() {
|
|
||||||
ConstrainedValue::Boolean(boolean) => Value::Boolean(boolean),
|
|
||||||
ConstrainedValue::Integer(integer) => match integer {
|
|
||||||
Integer::U8(u8) => Value::U8(u8),
|
|
||||||
Integer::U16(u16) => Value::U16(u16),
|
|
||||||
Integer::U32(u32) => Value::U32(u32),
|
|
||||||
Integer::U64(u64) => Value::U64(u64),
|
|
||||||
Integer::U128(u128) => Value::U128(u128),
|
|
||||||
|
|
||||||
Integer::I8(i8) => Value::I8(i8),
|
|
||||||
Integer::I16(i16) => Value::I16(i16),
|
|
||||||
Integer::I32(i32) => Value::I32(i32),
|
|
||||||
Integer::I64(i64) => Value::I64(i64),
|
|
||||||
Integer::I128(i128) => Value::I128(i128),
|
|
||||||
},
|
|
||||||
ConstrainedValue::Array(array) => {
|
|
||||||
let array_value = array.into_iter().map(|element| element.to_value()).collect();
|
|
||||||
|
|
||||||
Value::Array(array_value)
|
|
||||||
}
|
|
||||||
ConstrainedValue::Tuple(tuple) => {
|
|
||||||
let tuple_value = tuple.into_iter().map(|element| element.to_value()).collect();
|
|
||||||
|
|
||||||
Value::Tuple(tuple_value)
|
|
||||||
}
|
|
||||||
_ => unimplemented!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn resolve_type(&mut self, type_: Option<Type>, 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<Type>,
|
|
||||||
span: &Span,
|
|
||||||
) -> Result<(), ValueError> {
|
|
||||||
if type_.is_some() {
|
|
||||||
self.resolve_type(type_.clone(), span)?;
|
|
||||||
return other.resolve_type(type_, span);
|
|
||||||
}
|
|
||||||
|
|
||||||
match (&self, &other) {
|
|
||||||
(ConstrainedValue::Unresolved(_), ConstrainedValue::Unresolved(_)) => Ok(()),
|
|
||||||
(ConstrainedValue::Unresolved(_), _) => self.resolve_type(Some(other.to_type(span)?), span),
|
|
||||||
(_, ConstrainedValue::Unresolved(_)) => other.resolve_type(Some(self.to_type(span)?), span),
|
|
||||||
_ => Ok(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn extract_function(self, scope: &str, span: &Span) -> Result<(String, Function), ExpressionError> {
|
|
||||||
match self {
|
|
||||||
ConstrainedValue::Function(circuit_identifier, function) => {
|
|
||||||
let mut outer_scope = scope.to_string();
|
|
||||||
// If this is a circuit function, evaluate inside the circuit scope
|
|
||||||
if let Some(identifier) = circuit_identifier {
|
|
||||||
// avoid creating recursive scope
|
|
||||||
if !is_in_scope(&scope, &identifier.name) {
|
|
||||||
outer_scope = new_scope(scope, &identifier.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok((outer_scope, *function))
|
|
||||||
}
|
|
||||||
ConstrainedValue::Import(import_scope, function) => function.extract_function(&import_scope, span),
|
|
||||||
value => Err(ExpressionError::undefined_function(value.to_string(), span.to_owned())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn extract_circuit(self, span: &Span) -> Result<Circuit, ExpressionError> {
|
|
||||||
match self {
|
|
||||||
ConstrainedValue::CircuitDefinition(circuit) => Ok(circuit),
|
|
||||||
ConstrainedValue::Import(_import_scope, circuit) => circuit.extract_circuit(span),
|
|
||||||
value => Err(ExpressionError::undefined_circuit(value.to_string(), span.to_owned())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Modifies the `self` [ConstrainedValue] so there are no `mut` keywords wrapping the `self` value.
|
/// Modifies the `self` [ConstrainedValue] so there are no `mut` keywords wrapping the `self` value.
|
||||||
///
|
///
|
||||||
@ -241,85 +97,6 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
|
|||||||
*self = *inner.clone()
|
*self = *inner.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn allocate_value<CS: ConstraintSystem<F>>(
|
|
||||||
&mut self,
|
|
||||||
mut cs: CS,
|
|
||||||
span: &Span,
|
|
||||||
) -> Result<(), ValueError> {
|
|
||||||
match self {
|
|
||||||
// Data types
|
|
||||||
ConstrainedValue::Address(_address) => {
|
|
||||||
// allow `let address()` even though addresses are constant
|
|
||||||
}
|
|
||||||
ConstrainedValue::Boolean(boolean) => {
|
|
||||||
let option = boolean.get_value();
|
|
||||||
let name = option
|
|
||||||
.map(|b| b.to_string())
|
|
||||||
.unwrap_or_else(|| "[allocated]".to_string());
|
|
||||||
|
|
||||||
*boolean = allocate_bool(&mut cs, &name, option, span)?;
|
|
||||||
}
|
|
||||||
ConstrainedValue::Field(field) => {
|
|
||||||
let gadget = field
|
|
||||||
.allocated(cs.ns(|| format!("allocate field {}:{}", span.line, span.start)))
|
|
||||||
.map_err(|error| ValueError::FieldError(FieldError::synthesis_error(error, span.to_owned())))?;
|
|
||||||
|
|
||||||
*field = FieldType::Allocated(gadget)
|
|
||||||
}
|
|
||||||
ConstrainedValue::Group(group) => {
|
|
||||||
*group = group.to_allocated(cs, span)?;
|
|
||||||
}
|
|
||||||
ConstrainedValue::Integer(integer) => {
|
|
||||||
let integer_type = integer.get_type();
|
|
||||||
let option = integer.get_value();
|
|
||||||
let name = option.clone().unwrap_or_else(|| "[allocated]".to_string());
|
|
||||||
|
|
||||||
*integer = Integer::allocate_type(&mut cs, integer_type, &name, option, span)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Data type wrappers
|
|
||||||
ConstrainedValue::Array(array) => {
|
|
||||||
array.iter_mut().enumerate().try_for_each(|(i, value)| {
|
|
||||||
let unique_name = format!("allocate array member {} {}:{}", i, span.line, span.start);
|
|
||||||
|
|
||||||
value.allocate_value(cs.ns(|| unique_name), span)
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
ConstrainedValue::Tuple(tuple) => {
|
|
||||||
tuple.iter_mut().enumerate().try_for_each(|(i, value)| {
|
|
||||||
let unique_name = format!("allocate tuple member {} {}:{}", i, span.line, span.start);
|
|
||||||
|
|
||||||
value.allocate_value(cs.ns(|| unique_name), span)
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
ConstrainedValue::CircuitExpression(_id, members) => {
|
|
||||||
members.iter_mut().enumerate().try_for_each(|(i, member)| {
|
|
||||||
let unique_name = format!("allocate circuit member {} {}:{}", i, span.line, span.start);
|
|
||||||
|
|
||||||
member.1.allocate_value(cs.ns(|| unique_name), span)
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
ConstrainedValue::Mutable(value) => {
|
|
||||||
value.allocate_value(cs, span)?;
|
|
||||||
}
|
|
||||||
ConstrainedValue::Static(value) => {
|
|
||||||
value.allocate_value(cs, span)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Empty wrappers that are unreachable
|
|
||||||
ConstrainedValue::CircuitDefinition(_) => {}
|
|
||||||
ConstrainedValue::Function(_, _) => {}
|
|
||||||
ConstrainedValue::Import(_, _) => {}
|
|
||||||
|
|
||||||
// Cannot allocate an unresolved value
|
|
||||||
ConstrainedValue::Unresolved(value) => {
|
|
||||||
return Err(ValueError::implicit(value.to_string(), span.to_owned()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field + PrimeField, G: GroupType<F>> fmt::Display for ConstrainedValue<F, G> {
|
impl<F: Field + PrimeField, G: GroupType<F>> fmt::Display for ConstrainedValue<F, G> {
|
||||||
@ -355,8 +132,8 @@ impl<F: Field + PrimeField, G: GroupType<F>> fmt::Display for ConstrainedValue<F
|
|||||||
|
|
||||||
write!(f, "({})", values)
|
write!(f, "({})", values)
|
||||||
}
|
}
|
||||||
ConstrainedValue::CircuitExpression(ref identifier, ref members) => {
|
ConstrainedValue::CircuitExpression(ref circuit, ref members) => {
|
||||||
write!(f, "{} {{", identifier)?;
|
write!(f, "{} {{", circuit.circuit.name.borrow())?;
|
||||||
for (i, member) in members.iter().enumerate() {
|
for (i, member) in members.iter().enumerate() {
|
||||||
write!(f, "{}: {}", member.0, member.1)?;
|
write!(f, "{}: {}", member.0, member.1)?;
|
||||||
if i < members.len() - 1 {
|
if i < members.len() - 1 {
|
||||||
@ -365,14 +142,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> fmt::Display for ConstrainedValue<F
|
|||||||
}
|
}
|
||||||
write!(f, "}}")
|
write!(f, "}}")
|
||||||
}
|
}
|
||||||
ConstrainedValue::CircuitDefinition(ref circuit) => write!(f, "circuit {{ {} }}", circuit.circuit_name),
|
|
||||||
ConstrainedValue::Function(ref _circuit_option, ref function) => {
|
|
||||||
write!(f, "function {{ {}() }}", function.identifier)
|
|
||||||
}
|
|
||||||
ConstrainedValue::Import(_, ref value) => write!(f, "{}", value),
|
|
||||||
ConstrainedValue::Mutable(ref value) => write!(f, "{}", value),
|
ConstrainedValue::Mutable(ref value) => write!(f, "{}", value),
|
||||||
ConstrainedValue::Static(ref value) => write!(f, "{}", value),
|
|
||||||
ConstrainedValue::Unresolved(ref value) => write!(f, "{}", value),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -478,11 +248,6 @@ impl<F: Field + PrimeField, G: GroupType<F>> CondSelectGadget<F> for Constrained
|
|||||||
|
|
||||||
ConstrainedValue::Tuple(array)
|
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_1),
|
||||||
ConstrainedValue::CircuitExpression(_identifier, members_2),
|
ConstrainedValue::CircuitExpression(_identifier, members_2),
|
||||||
@ -500,11 +265,6 @@ impl<F: Field + PrimeField, G: GroupType<F>> CondSelectGadget<F> for Constrained
|
|||||||
|
|
||||||
ConstrainedValue::CircuitExpression(identifier.clone(), members)
|
ConstrainedValue::CircuitExpression(identifier.clone(), members)
|
||||||
}
|
}
|
||||||
(ConstrainedValue::Static(first), ConstrainedValue::Static(second)) => {
|
|
||||||
let value = Self::conditionally_select(cs, cond, first, second)?;
|
|
||||||
|
|
||||||
ConstrainedValue::Static(Box::new(value))
|
|
||||||
}
|
|
||||||
(ConstrainedValue::Mutable(first), _) => Self::conditionally_select(cs, cond, first, second)?,
|
(ConstrainedValue::Mutable(first), _) => Self::conditionally_select(cs, cond, first, second)?,
|
||||||
(_, ConstrainedValue::Mutable(second)) => Self::conditionally_select(cs, cond, first, second)?,
|
(_, ConstrainedValue::Mutable(second)) => Self::conditionally_select(cs, cond, first, second)?,
|
||||||
(_, _) => return Err(SynthesisError::Unsatisfiable),
|
(_, _) => return Err(SynthesisError::Unsatisfiable),
|
||||||
@ -533,25 +293,3 @@ impl<F: Field + PrimeField, G: GroupType<F>> CondSelectGadget<F> for Constrained
|
|||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field + PrimeField, G: GroupType<F>> From<Value> for ConstrainedValue<F, G> {
|
|
||||||
fn from(v: Value) -> Self {
|
|
||||||
match v {
|
|
||||||
Value::Boolean(boolean) => ConstrainedValue::Boolean(boolean),
|
|
||||||
Value::U8(u8) => ConstrainedValue::Integer(Integer::U8(u8)),
|
|
||||||
Value::U16(u16) => ConstrainedValue::Integer(Integer::U16(u16)),
|
|
||||||
Value::U32(u32) => ConstrainedValue::Integer(Integer::U32(u32)),
|
|
||||||
Value::U64(u64) => ConstrainedValue::Integer(Integer::U64(u64)),
|
|
||||||
Value::U128(u128) => ConstrainedValue::Integer(Integer::U128(u128)),
|
|
||||||
|
|
||||||
Value::I8(i8) => ConstrainedValue::Integer(Integer::I8(i8)),
|
|
||||||
Value::I16(i16) => ConstrainedValue::Integer(Integer::I16(i16)),
|
|
||||||
Value::I32(i32) => ConstrainedValue::Integer(Integer::I32(i32)),
|
|
||||||
Value::I64(i64) => ConstrainedValue::Integer(Integer::I64(i64)),
|
|
||||||
Value::I128(i128) => ConstrainedValue::Integer(Integer::I128(i128)),
|
|
||||||
|
|
||||||
Value::Array(array) => ConstrainedValue::Array(array.into_iter().map(ConstrainedValue::from).collect()),
|
|
||||||
Value::Tuple(tuple) => ConstrainedValue::Tuple(tuple.into_iter().map(ConstrainedValue::from).collect()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{assert_satisfied, expect_compiler_error, generate_main_input, parse_program};
|
use crate::{assert_satisfied, expect_asg_error, expect_compiler_error, generate_main_input, parse_program};
|
||||||
use leo_ast::InputValue;
|
use leo_ast::InputValue;
|
||||||
|
|
||||||
static TEST_ADDRESS_1: &str = "aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8sta57j8";
|
static TEST_ADDRESS_1: &str = "aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8sta57j8";
|
||||||
@ -63,9 +63,9 @@ fn test_implicit_valid() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_implicit_invalid() {
|
fn test_implicit_invalid() {
|
||||||
let program_string = include_str!("implicit_invalid.leo");
|
let program_string = include_str!("implicit_invalid.leo");
|
||||||
let program = parse_program(program_string).unwrap();
|
let error = parse_program(program_string).err().unwrap();
|
||||||
|
|
||||||
let _output = expect_compiler_error(program);
|
expect_asg_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
assert_satisfied,
|
assert_satisfied,
|
||||||
|
expect_asg_error,
|
||||||
expect_compiler_error,
|
expect_compiler_error,
|
||||||
get_output,
|
get_output,
|
||||||
parse_program,
|
parse_program,
|
||||||
@ -67,6 +68,14 @@ fn test_inline() {
|
|||||||
assert_satisfied(program);
|
assert_satisfied(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_nested() {
|
||||||
|
let program_string = include_str!("nested.leo");
|
||||||
|
let program = parse_program(program_string).unwrap();
|
||||||
|
|
||||||
|
assert_satisfied(program);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_inline_fail() {
|
fn test_inline_fail() {
|
||||||
let program_string = include_str!("inline.leo");
|
let program_string = include_str!("inline.leo");
|
||||||
@ -150,17 +159,17 @@ fn test_input_tuple_3x2_fail() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_multi_fail_initializer() {
|
fn test_multi_fail_initializer() {
|
||||||
let program_string = include_str!("multi_fail_initializer.leo");
|
let program_string = include_str!("multi_fail_initializer.leo");
|
||||||
let program = parse_program(program_string).unwrap();
|
let error = parse_program(program_string).err().unwrap();
|
||||||
|
|
||||||
let _err = expect_compiler_error(program);
|
expect_asg_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_multi_inline_fail() {
|
fn test_multi_inline_fail() {
|
||||||
let program_string = include_str!("multi_fail_inline.leo");
|
let program_string = include_str!("multi_fail_inline.leo");
|
||||||
let program = parse_program(program_string).unwrap();
|
let error = parse_program(program_string).err().unwrap();
|
||||||
|
|
||||||
let _err = expect_compiler_error(program);
|
expect_asg_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -174,9 +183,9 @@ fn test_multi_initializer() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_multi_initializer_fail() {
|
fn test_multi_initializer_fail() {
|
||||||
let program_string = include_str!("multi_initializer_fail.leo");
|
let program_string = include_str!("multi_initializer_fail.leo");
|
||||||
let program = parse_program(program_string).unwrap();
|
let error = parse_program(program_string).err().unwrap();
|
||||||
|
|
||||||
let _err = expect_compiler_error(program);
|
expect_asg_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -190,9 +199,9 @@ fn test_nested_3x2_value() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_nested_3x2_value_fail() {
|
fn test_nested_3x2_value_fail() {
|
||||||
let program_string = include_str!("nested_3x2_value_fail.leo");
|
let program_string = include_str!("nested_3x2_value_fail.leo");
|
||||||
let program = parse_program(program_string).unwrap();
|
let error = parse_program(program_string).err().unwrap();
|
||||||
|
|
||||||
let _err = expect_compiler_error(program);
|
expect_asg_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -206,9 +215,9 @@ fn test_tuple_3x2_value() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_tuple_3x2_value_fail() {
|
fn test_tuple_3x2_value_fail() {
|
||||||
let program_string = include_str!("tuple_3x2_value_fail.leo");
|
let program_string = include_str!("tuple_3x2_value_fail.leo");
|
||||||
let program = parse_program(program_string).unwrap();
|
let error = parse_program(program_string).err().unwrap();
|
||||||
|
|
||||||
let _err = expect_compiler_error(program);
|
expect_asg_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -258,9 +267,9 @@ fn test_type_nested_value_nested_3x2() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_type_nested_value_nested_3x2_fail() {
|
fn test_type_nested_value_nested_3x2_fail() {
|
||||||
let program_string = include_str!("type_nested_value_nested_3x2_fail.leo");
|
let program_string = include_str!("type_nested_value_nested_3x2_fail.leo");
|
||||||
let program = parse_program(program_string).unwrap();
|
let error = parse_program(program_string).err().unwrap();
|
||||||
|
|
||||||
let _err = expect_compiler_error(program);
|
expect_asg_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -274,9 +283,9 @@ fn test_type_nested_value_nested_4x3x2() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_type_nested_value_nested_4x3x2_fail() {
|
fn test_type_nested_value_nested_4x3x2_fail() {
|
||||||
let program_string = include_str!("type_nested_value_nested_4x3x2_fail.leo");
|
let program_string = include_str!("type_nested_value_nested_4x3x2_fail.leo");
|
||||||
let program = parse_program(program_string).unwrap();
|
let error = parse_program(program_string).err().unwrap();
|
||||||
|
|
||||||
let _err = expect_compiler_error(program);
|
expect_asg_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -290,9 +299,9 @@ fn test_type_nested_value_tuple_3x2() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_type_nested_value_tuple_3x2_fail() {
|
fn test_type_nested_value_tuple_3x2_fail() {
|
||||||
let program_string = include_str!("type_nested_value_tuple_3x2_fail.leo");
|
let program_string = include_str!("type_nested_value_tuple_3x2_fail.leo");
|
||||||
let program = parse_program(program_string).unwrap();
|
let error = parse_program(program_string).err().unwrap();
|
||||||
|
|
||||||
let _err = expect_compiler_error(program);
|
expect_asg_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -306,9 +315,9 @@ fn test_type_nested_value_tuple_4x3x2() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_type_nested_value_tuple_4x3x2_fail() {
|
fn test_type_nested_value_tuple_4x3x2_fail() {
|
||||||
let program_string = include_str!("type_nested_value_tuple_4x3x2_fail.leo");
|
let program_string = include_str!("type_nested_value_tuple_4x3x2_fail.leo");
|
||||||
let program = parse_program(program_string).unwrap();
|
let error = parse_program(program_string).err().unwrap();
|
||||||
|
|
||||||
let _err = expect_compiler_error(program);
|
expect_asg_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -322,9 +331,9 @@ fn test_type_tuple_value_nested_3x2() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_type_tuple_value_nested_3x2_fail() {
|
fn test_type_tuple_value_nested_3x2_fail() {
|
||||||
let program_string = include_str!("type_tuple_value_nested_3x2_fail.leo");
|
let program_string = include_str!("type_tuple_value_nested_3x2_fail.leo");
|
||||||
let program = parse_program(program_string).unwrap();
|
let error = parse_program(program_string).err().unwrap();
|
||||||
|
|
||||||
let _err = expect_compiler_error(program);
|
expect_asg_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -338,9 +347,9 @@ fn test_type_tuple_value_nested_4x3x2() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_type_tuple_value_nested_4x3x2_fail() {
|
fn test_type_tuple_value_nested_4x3x2_fail() {
|
||||||
let program_string = include_str!("type_tuple_value_nested_4x3x2_fail.leo");
|
let program_string = include_str!("type_tuple_value_nested_4x3x2_fail.leo");
|
||||||
let program = parse_program(program_string).unwrap();
|
let error = parse_program(program_string).err().unwrap();
|
||||||
|
|
||||||
let _err = expect_compiler_error(program);
|
expect_asg_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -354,9 +363,9 @@ fn test_type_tuple_value_tuple_3x2() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_type_tuple_value_tuple_3x2_fail() {
|
fn test_type_tuple_value_tuple_3x2_fail() {
|
||||||
let program_string = include_str!("type_tuple_value_tuple_3x2_fail.leo");
|
let program_string = include_str!("type_tuple_value_tuple_3x2_fail.leo");
|
||||||
let program = parse_program(program_string).unwrap();
|
let error = parse_program(program_string).err().unwrap();
|
||||||
|
|
||||||
let _err = expect_compiler_error(program);
|
expect_asg_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -370,9 +379,9 @@ fn test_type_tuple_value_tuple_4x3x2() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_type_tuple_value_tuple_4x3x2_fail() {
|
fn test_type_tuple_value_tuple_4x3x2_fail() {
|
||||||
let program_string = include_str!("type_tuple_value_tuple_4x3x2_fail.leo");
|
let program_string = include_str!("type_tuple_value_tuple_4x3x2_fail.leo");
|
||||||
let program = parse_program(program_string).unwrap();
|
let error = parse_program(program_string).err().unwrap();
|
||||||
|
|
||||||
let _err = expect_compiler_error(program);
|
expect_asg_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests for nested multi-dimensional arrays as input to the program
|
// Tests for nested multi-dimensional arrays as input to the program
|
||||||
@ -522,3 +531,11 @@ fn test_input_type_tuple_value_tuple_4x3x2_fail() {
|
|||||||
|
|
||||||
assert!(syntax_error);
|
assert!(syntax_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_variable_slice_fail() {
|
||||||
|
let program_string = include_str!("variable_slice_fail.leo");
|
||||||
|
let error = parse_program(program_string).err().unwrap();
|
||||||
|
|
||||||
|
expect_asg_error(error);
|
||||||
|
}
|
||||||
|
4
compiler/tests/array/nested.leo
Normal file
4
compiler/tests/array/nested.leo
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
function main () {
|
||||||
|
let x = [false; (2, 2)];
|
||||||
|
let y: bool = x[0][0];
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
function main() {
|
function main() {
|
||||||
const a = [[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]]; // inline
|
const a = [[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]]; // inline
|
||||||
|
|
||||||
const b: [u8; (2, 3)] = [[0; 3]; 2]; // initializer
|
const b: [u8; (3, 2)] = [[0; 2]; 3]; // initializer
|
||||||
|
|
||||||
console.assert(a == b);
|
console.assert(a == b);
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
function main() {
|
function main() {
|
||||||
const a = [[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]]; // inline
|
const a = [[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]]; // inline
|
||||||
|
|
||||||
const b: [u8; (2, 3)] = [0; (2, 3)]; // initializer
|
const b: [u8; (3, 2)] = [0; (3, 2)]; // initializer
|
||||||
|
|
||||||
console.assert(a == b);
|
console.assert(a == b);
|
||||||
}
|
}
|
7
compiler/tests/array/variable_slice_fail.leo
Normal file
7
compiler/tests/array/variable_slice_fail.leo
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
function main() {
|
||||||
|
let a = [1u8; 10];
|
||||||
|
for i in 0..10 {
|
||||||
|
let x = a[i..10];
|
||||||
|
console.debug("{}", x);
|
||||||
|
}
|
||||||
|
}
|
@ -16,8 +16,8 @@
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
assert_satisfied,
|
assert_satisfied,
|
||||||
|
expect_asg_error,
|
||||||
expect_compiler_error,
|
expect_compiler_error,
|
||||||
expect_type_inference_error,
|
|
||||||
get_output,
|
get_output,
|
||||||
parse_program,
|
parse_program,
|
||||||
parse_program_with_input,
|
parse_program_with_input,
|
||||||
@ -104,9 +104,9 @@ fn test_not_mutable() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_not_u32() {
|
fn test_not_u32() {
|
||||||
let program_string = include_str!("not_u32.leo");
|
let program_string = include_str!("not_u32.leo");
|
||||||
let program = parse_program(program_string).unwrap();
|
let error = parse_program(program_string).err().unwrap();
|
||||||
|
|
||||||
expect_compiler_error(program);
|
expect_asg_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Boolean or ||
|
// Boolean or ||
|
||||||
@ -140,7 +140,7 @@ fn test_true_or_u32() {
|
|||||||
let program_string = include_str!("true_or_u32.leo");
|
let program_string = include_str!("true_or_u32.leo");
|
||||||
let error = parse_program(program_string).err().unwrap();
|
let error = parse_program(program_string).err().unwrap();
|
||||||
|
|
||||||
expect_type_inference_error(error);
|
expect_asg_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Boolean and &&
|
// Boolean and &&
|
||||||
@ -174,7 +174,7 @@ fn test_true_and_u32() {
|
|||||||
let program_string = include_str!("true_and_u32.leo");
|
let program_string = include_str!("true_and_u32.leo");
|
||||||
let error = parse_program(program_string).err().unwrap();
|
let error = parse_program(program_string).err().unwrap();
|
||||||
|
|
||||||
expect_type_inference_error(error);
|
expect_asg_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// All
|
// All
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
circuit Foo {
|
circuit Foo {
|
||||||
function echo(x: u32) -> u32 {
|
x: u32,
|
||||||
return x
|
|
||||||
|
function echo(self) -> u32 {
|
||||||
|
return self.x
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function main() {
|
function main() {
|
||||||
let a = Foo { };
|
let a = Foo { x: 1u32 };
|
||||||
|
|
||||||
console.assert(a.echo(1u32) == 1u32);
|
console.assert(a.echo() == 1u32);
|
||||||
}
|
}
|
@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{assert_satisfied, expect_compiler_error, expect_type_inference_error, parse_program};
|
use crate::{assert_satisfied, expect_asg_error, parse_program};
|
||||||
|
|
||||||
// Expressions
|
// Expressions
|
||||||
|
|
||||||
@ -29,9 +29,9 @@ fn test_inline() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_inline_fail() {
|
fn test_inline_fail() {
|
||||||
let program_string = include_str!("inline_fail.leo");
|
let program_string = include_str!("inline_fail.leo");
|
||||||
let program = parse_program(program_string).unwrap();
|
let error = parse_program(program_string).err().unwrap();
|
||||||
|
|
||||||
expect_compiler_error(program);
|
expect_asg_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -39,7 +39,7 @@ fn test_inline_undefined() {
|
|||||||
let program_string = include_str!("inline_undefined.leo");
|
let program_string = include_str!("inline_undefined.leo");
|
||||||
let error = parse_program(program_string).err().unwrap();
|
let error = parse_program(program_string).err().unwrap();
|
||||||
|
|
||||||
expect_type_inference_error(error);
|
expect_asg_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Members
|
// Members
|
||||||
@ -57,7 +57,7 @@ fn test_member_variable_fail() {
|
|||||||
let program_string = include_str!("member_variable_fail.leo");
|
let program_string = include_str!("member_variable_fail.leo");
|
||||||
let error = parse_program(program_string).err().unwrap();
|
let error = parse_program(program_string).err().unwrap();
|
||||||
|
|
||||||
expect_type_inference_error(error);
|
expect_asg_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -81,7 +81,7 @@ fn test_member_function_fail() {
|
|||||||
let program_string = include_str!("member_function_fail.leo");
|
let program_string = include_str!("member_function_fail.leo");
|
||||||
let error = parse_program(program_string).err().unwrap();
|
let error = parse_program(program_string).err().unwrap();
|
||||||
|
|
||||||
expect_type_inference_error(error);
|
expect_asg_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -89,7 +89,7 @@ fn test_member_function_invalid() {
|
|||||||
let program_string = include_str!("member_function_invalid.leo");
|
let program_string = include_str!("member_function_invalid.leo");
|
||||||
let error = parse_program(program_string).err().unwrap();
|
let error = parse_program(program_string).err().unwrap();
|
||||||
|
|
||||||
expect_type_inference_error(error);
|
expect_asg_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -121,7 +121,7 @@ fn test_member_static_function_invalid() {
|
|||||||
let program_string = include_str!("member_static_function_invalid.leo");
|
let program_string = include_str!("member_static_function_invalid.leo");
|
||||||
let error = parse_program(program_string).err().unwrap();
|
let error = parse_program(program_string).err().unwrap();
|
||||||
|
|
||||||
expect_type_inference_error(error)
|
expect_asg_error(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -129,7 +129,7 @@ fn test_member_static_function_undefined() {
|
|||||||
let program_string = include_str!("member_static_function_undefined.leo");
|
let program_string = include_str!("member_static_function_undefined.leo");
|
||||||
let error = parse_program(program_string).err().unwrap();
|
let error = parse_program(program_string).err().unwrap();
|
||||||
|
|
||||||
expect_type_inference_error(error)
|
expect_asg_error(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mutability
|
// Mutability
|
||||||
@ -139,7 +139,7 @@ fn test_mutate_function_fail() {
|
|||||||
let program_string = include_str!("mut_function_fail.leo");
|
let program_string = include_str!("mut_function_fail.leo");
|
||||||
let error = parse_program(program_string).err().unwrap();
|
let error = parse_program(program_string).err().unwrap();
|
||||||
|
|
||||||
expect_type_inference_error(error);
|
expect_asg_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -150,6 +150,14 @@ fn test_mutate_self_variable() {
|
|||||||
assert_satisfied(program);
|
assert_satisfied(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mutate_self_variable_branch() {
|
||||||
|
let program_string = include_str!("mut_self_variable_branch.leo");
|
||||||
|
let program = parse_program(program_string).unwrap();
|
||||||
|
|
||||||
|
assert_satisfied(program);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mutate_self_variable_conditional() {
|
fn test_mutate_self_variable_conditional() {
|
||||||
let program_string = include_str!("mut_self_variable_conditional.leo");
|
let program_string = include_str!("mut_self_variable_conditional.leo");
|
||||||
@ -161,9 +169,9 @@ fn test_mutate_self_variable_conditional() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_mutate_self_variable_fail() {
|
fn test_mutate_self_variable_fail() {
|
||||||
let program_string = include_str!("mut_self_variable_fail.leo");
|
let program_string = include_str!("mut_self_variable_fail.leo");
|
||||||
let program = parse_program(program_string).unwrap();
|
let error = parse_program(program_string).err().unwrap();
|
||||||
|
|
||||||
expect_compiler_error(program);
|
expect_asg_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -171,7 +179,7 @@ fn test_mutate_self_function_fail() {
|
|||||||
let program_string = include_str!("mut_self_function_fail.leo");
|
let program_string = include_str!("mut_self_function_fail.leo");
|
||||||
let error = parse_program(program_string).err().unwrap();
|
let error = parse_program(program_string).err().unwrap();
|
||||||
|
|
||||||
expect_type_inference_error(error);
|
expect_asg_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -179,7 +187,7 @@ fn test_mutate_self_static_function_fail() {
|
|||||||
let program_string = include_str!("mut_self_static_function_fail.leo");
|
let program_string = include_str!("mut_self_static_function_fail.leo");
|
||||||
let error = parse_program(program_string).err().unwrap();
|
let error = parse_program(program_string).err().unwrap();
|
||||||
|
|
||||||
expect_type_inference_error(error);
|
expect_asg_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -187,7 +195,7 @@ fn test_mutate_static_function_fail() {
|
|||||||
let program_string = include_str!("mut_static_function_fail.leo");
|
let program_string = include_str!("mut_static_function_fail.leo");
|
||||||
let error = parse_program(program_string).err().unwrap();
|
let error = parse_program(program_string).err().unwrap();
|
||||||
|
|
||||||
expect_type_inference_error(error);
|
expect_asg_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -201,9 +209,9 @@ fn test_mutate_variable() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_mutate_variable_fail() {
|
fn test_mutate_variable_fail() {
|
||||||
let program_string = include_str!("mut_variable_fail.leo");
|
let program_string = include_str!("mut_variable_fail.leo");
|
||||||
let program = parse_program(program_string).unwrap();
|
let error = parse_program(program_string).err().unwrap();
|
||||||
|
|
||||||
expect_compiler_error(program);
|
expect_asg_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Self
|
// Self
|
||||||
@ -213,7 +221,7 @@ fn test_self_fail() {
|
|||||||
let program_string = include_str!("self_fail.leo");
|
let program_string = include_str!("self_fail.leo");
|
||||||
let error = parse_program(program_string).err().unwrap();
|
let error = parse_program(program_string).err().unwrap();
|
||||||
|
|
||||||
expect_type_inference_error(error);
|
expect_asg_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -229,7 +237,7 @@ fn test_self_member_invalid() {
|
|||||||
let program_string = include_str!("self_member_invalid.leo");
|
let program_string = include_str!("self_member_invalid.leo");
|
||||||
let error = parse_program(program_string).err().unwrap();
|
let error = parse_program(program_string).err().unwrap();
|
||||||
|
|
||||||
expect_type_inference_error(error);
|
expect_asg_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -237,7 +245,7 @@ fn test_self_member_undefined() {
|
|||||||
let program_string = include_str!("self_member_undefined.leo");
|
let program_string = include_str!("self_member_undefined.leo");
|
||||||
let error = parse_program(program_string).err().unwrap();
|
let error = parse_program(program_string).err().unwrap();
|
||||||
|
|
||||||
expect_type_inference_error(error);
|
expect_asg_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// All
|
// All
|
||||||
|
32
compiler/tests/circuits/mut_self_variable_branch.leo
Normal file
32
compiler/tests/circuits/mut_self_variable_branch.leo
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
circuit Foo {
|
||||||
|
a: u8,
|
||||||
|
|
||||||
|
function set_a(mut self, condition: bool, new: u8) {
|
||||||
|
if condition {
|
||||||
|
self.a = new;
|
||||||
|
console.assert(self.a == new);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function main() {
|
||||||
|
let mut f = Foo { a: 0u8 };
|
||||||
|
|
||||||
|
console.assert(f.a == 0u8);
|
||||||
|
|
||||||
|
f.set_a(false, 1u8);
|
||||||
|
|
||||||
|
console.assert(f.a == 0u8);
|
||||||
|
|
||||||
|
f.set_a(true, 1u8);
|
||||||
|
|
||||||
|
console.assert(f.a == 1u8);
|
||||||
|
|
||||||
|
f.set_a(false, 2u8);
|
||||||
|
|
||||||
|
console.assert(f.a == 1u8);
|
||||||
|
|
||||||
|
f.set_a(true, 2u8);
|
||||||
|
|
||||||
|
console.assert(f.a == 2u8);
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user