diff --git a/asg/src/const_value.rs b/asg/src/const_value.rs index f093a65559..c0ddb90d07 100644 --- a/asg/src/const_value.rs +++ b/asg/src/const_value.rs @@ -91,6 +91,16 @@ pub enum GroupValue { Tuple(GroupCoordinate, GroupCoordinate), } +impl From for GroupValue { + fn from(other: leo_ast::GroupValue) -> Self { + use leo_ast::GroupValue::*; + match other { + Single(value, _) => GroupValue::Single(value), + Tuple(value) => GroupValue::Tuple(GroupCoordinate::from(&value.x), GroupCoordinate::from(&value.y)), + } + } +} + #[derive(Clone, Debug, PartialEq)] pub enum ConstValue { Int(ConstInt), diff --git a/ast/src/input/input.rs b/ast/src/input/input.rs index ae201c2aec..628f5cd750 100644 --- a/ast/src/input/input.rs +++ b/ast/src/input/input.rs @@ -94,9 +94,10 @@ impl Input { Ok(()) } - /// Returns the main function input value with the given `name` + /// Returns the main function input value with the given `name`, second parameter + /// is a boolean indicating whether parameter is const. #[allow(clippy::ptr_arg)] - pub fn get(&self, name: &String) -> Option> { + pub fn get(&self, name: &String) -> Option<(Option, bool)> { self.program_input.get(name) } diff --git a/ast/src/input/program_input/main_input.rs b/ast/src/input/program_input/main_input.rs index 7d1b496134..66b2ed5b61 100644 --- a/ast/src/input/program_input/main_input.rs +++ b/ast/src/input/program_input/main_input.rs @@ -22,6 +22,7 @@ use indexmap::IndexMap; #[derive(Clone, PartialEq, Eq, Default)] pub struct MainInput { input: IndexMap>, + constants: IndexMap>, } #[allow(clippy::len_without_is_empty)] @@ -34,16 +35,21 @@ impl MainInput { /// Called during constraint synthesis to provide private input variables. pub fn empty(&self) -> Self { let mut input = self.input.clone(); + let mut constants = self.constants.clone(); input.iter_mut().for_each(|(_name, value)| { *value = None; }); - Self { input } + constants.iter_mut().for_each(|(_name, value)| { + *value = None; + }); + + Self { input, constants } } pub fn len(&self) -> usize { - self.input.len() + self.input.len() + self.constants.len() } pub fn insert(&mut self, key: String, value: Option) { @@ -54,16 +60,27 @@ impl MainInput { pub fn parse(&mut self, definitions: Vec) -> Result<(), InputParserError> { for definition in definitions { let name = definition.parameter.variable.value; + let is_const = definition.const_.is_some(); let value = InputValue::from_expression(definition.parameter.type_, definition.expression)?; - self.insert(name, Some(value)); + if is_const { + self.constants.insert(name, Some(value)); + } else { + self.input.insert(name, Some(value)); + } } Ok(()) } - /// Returns an `Option` of the main function input at `name` - pub fn get(&self, name: &str) -> Option> { - self.input.get(name).cloned() + /// Returns an `Option` of the main function input at `name`. As a second + /// value in a tuple returns flag whether input is defined as a constant in input file. + pub fn get(&self, name: &str) -> Option<(Option, bool)> { + // As we check key presence in IndexMap unwraps below can be considered secure. + match (self.input.contains_key(name), self.constants.contains_key(name)) { + (true, _) => Some((self.input.get(name).cloned().unwrap(), false)), + (_, true) => Some((self.constants.get(name).cloned().unwrap(), true)), + (_, _) => None, + } } } diff --git a/ast/src/input/program_input/program_input.rs b/ast/src/input/program_input/program_input.rs index 42efab1a25..d2a7ef4f68 100644 --- a/ast/src/input/program_input/program_input.rs +++ b/ast/src/input/program_input/program_input.rs @@ -66,7 +66,7 @@ impl ProgramInput { /// Returns the main function input value with the given `name` #[allow(clippy::ptr_arg)] - pub fn get(&self, name: &String) -> Option> { + pub fn get(&self, name: &String) -> Option<(Option, bool)> { self.main.get(name) } diff --git a/ast/src/types/integer_type.rs b/ast/src/types/integer_type.rs index 579ca2c6c0..e2f3cab5bc 100644 --- a/ast/src/types/integer_type.rs +++ b/ast/src/types/integer_type.rs @@ -23,7 +23,7 @@ use leo_input::types::{ use serde::{Deserialize, Serialize}; use std::fmt; -/// Explicit integer type +/// Explicit integer type. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum IntegerType { U8, diff --git a/compiler/src/compiler.rs b/compiler/src/compiler.rs index c5f2a3b880..bdbf51b913 100644 --- a/compiler/src/compiler.rs +++ b/compiler/src/compiler.rs @@ -172,7 +172,6 @@ impl<'a, F: PrimeField, G: GroupType> Compiler<'a, F, G> { e })?; - self.program_input.parse_input(input_syntax_tree).map_err(|mut e| { e.set_path( input_path.to_str().unwrap_or_default(), diff --git a/compiler/src/expression/arithmetic/bit_not.rs b/compiler/src/expression/arithmetic/bit_not.rs index c040836e61..361abcdbfb 100644 --- a/compiler/src/expression/arithmetic/bit_not.rs +++ b/compiler/src/expression/arithmetic/bit_not.rs @@ -25,8 +25,5 @@ pub fn evaluate_bit_not<'a, F: PrimeField, G: GroupType>( value: ConstrainedValue<'a, F, G>, span: &Span, ) -> Result, IntegerError> { - match value { - // ConstrainedValue::Integer(i) => Ok(ConstrainedValue::Integer(i.not())), - value => Err(IntegerError::cannot_evaluate(format!("~{}", value), span)), - } + Err(IntegerError::cannot_evaluate(format!("~{}", value), span)) } diff --git a/compiler/src/function/input/main_function_input.rs b/compiler/src/function/input/main_function_input.rs index cbf9150a64..866263d188 100644 --- a/compiler/src/function/input/main_function_input.rs +++ b/compiler/src/function/input/main_function_input.rs @@ -26,15 +26,19 @@ use crate::{ group::input::group_from_input, ConstrainedValue, }, + FieldType, GroupType, Integer, }; -use leo_asg::Type; -use leo_ast::{InputValue, Span}; +use leo_asg::{ConstInt, Type}; +use leo_ast::{InputValue, IntegerType, Span}; use snarkvm_fields::PrimeField; +use snarkvm_gadgets::traits::utilities::boolean::Boolean; use snarkvm_r1cs::ConstraintSystem; +// use crate::value::{Address, ConstrainedValue, Integer}; + impl<'a, F: PrimeField, G: GroupType> ConstrainedProgram<'a, F, G> { pub fn allocate_main_function_input>( &mut self, @@ -62,3 +66,48 @@ impl<'a, F: PrimeField, G: GroupType> ConstrainedProgram<'a, F, G> { } } } + +/// Process constant inputs and return ConstrainedValue with constant value in it. +impl<'a, F: PrimeField, G: GroupType> ConstrainedProgram<'a, F, G> { + pub fn parse_constant_main_function_input>( + &mut self, + // TODO: remove unnecessary arguments + _cs: &mut CS, + _type_: &Type, + name: &str, + input_option: Option, + span: &Span, + ) -> Result, FunctionError> { + let value = input_option.unwrap(); + + Ok(match value { + InputValue::Address(value) => ConstrainedValue::Address(Address::constant(value, span)?), + InputValue::Boolean(value) => ConstrainedValue::Boolean(Boolean::constant(value)), + InputValue::Field(value) => ConstrainedValue::Field(FieldType::constant(value, span)?), + InputValue::Group(value) => ConstrainedValue::Group(G::constant(&value.into(), span)?), + InputValue::Integer(integer_type, value) => { + let integer = IntegerType::from(integer_type); + let const_int = match integer { + IntegerType::U8 => ConstInt::U8(value.parse::().unwrap()), + IntegerType::U16 => ConstInt::U16(value.parse::().unwrap()), + IntegerType::U32 => ConstInt::U32(value.parse::().unwrap()), + IntegerType::U64 => ConstInt::U64(value.parse::().unwrap()), + IntegerType::U128 => ConstInt::U128(value.parse::().unwrap()), + + IntegerType::I8 => ConstInt::I8(value.parse::().unwrap()), + IntegerType::I16 => ConstInt::I16(value.parse::().unwrap()), + IntegerType::I32 => ConstInt::I32(value.parse::().unwrap()), + IntegerType::I64 => ConstInt::I64(value.parse::().unwrap()), + IntegerType::I128 => ConstInt::I128(value.parse::().unwrap()), + }; + + ConstrainedValue::Integer(Integer::new(&const_int)) + } + // TODO: array and tuple values. + // InputValue::Array(Vec) => , + // InputValue::Tuple(Vec), + // TODO: rework this error to something better fitting into context. + _ => return Err(FunctionError::input_not_found(name.to_string(), span)), + }) + } +} diff --git a/compiler/src/function/main_function.rs b/compiler/src/function/main_function.rs index 8a77d3fd21..4833f4958e 100644 --- a/compiler/src/function/main_function.rs +++ b/compiler/src/function/main_function.rs @@ -61,16 +61,28 @@ impl<'a, F: PrimeField, G: GroupType> ConstrainedProgram<'a, F, G> { { let input_variable = input_variable.get().borrow(); let name = input_variable.name.name.clone(); - let input_option = input.get(&name).ok_or_else(|| { + + let (input_option, is_const) = 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_.clone(), - &name, - input_option, - &function.span.clone().unwrap_or_default(), - )?; + + let input_value = if is_const { + self.parse_constant_main_function_input( + cs, + &input_variable.type_.clone(), + &name, + input_option, + &function.span.clone().unwrap_or_default(), + )? + } else { + self.allocate_main_function_input( + cs, + &input_variable.type_.clone(), + &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); diff --git a/input/src/definitions/const_.rs b/input/src/definitions/const_.rs new file mode 100644 index 0000000000..b9dff97f29 --- /dev/null +++ b/input/src/definitions/const_.rs @@ -0,0 +1,27 @@ +// Copyright (C) 2019-2021 Aleo Systems Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use crate::ast::Rule; + +use pest::Span; +use pest_ast::FromPest; + +#[derive(Clone, Debug, FromPest, PartialEq)] +#[pest_ast(rule(Rule::const_))] +pub struct Const<'ast> { + #[pest_ast(outer())] + pub span: Span<'ast>, +} diff --git a/input/src/definitions/definition.rs b/input/src/definitions/definition.rs index c0c64bbe67..10dec65811 100644 --- a/input/src/definitions/definition.rs +++ b/input/src/definitions/definition.rs @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . +use super::Const; use crate::{ast::Rule, common::LineEnd, expressions::Expression, parameters::Parameter}; use pest::Span; @@ -22,9 +23,17 @@ use pest_ast::FromPest; #[derive(Clone, Debug, FromPest, PartialEq)] #[pest_ast(rule(Rule::definition))] pub struct Definition<'ast> { + pub const_: Option>, pub parameter: Parameter<'ast>, pub expression: Expression<'ast>, pub line_end: LineEnd, #[pest_ast(outer())] pub span: Span<'ast>, } + +impl<'ast> Definition<'ast> { + /// Check whether `const` keyword is placed before definition. + pub fn is_const(&self) -> bool { + self.const_.is_some() + } +} diff --git a/input/src/definitions/mod.rs b/input/src/definitions/mod.rs index d59ffd9d5d..e79c5ff093 100644 --- a/input/src/definitions/mod.rs +++ b/input/src/definitions/mod.rs @@ -16,3 +16,6 @@ pub mod definition; pub use definition::*; + +pub mod const_; +pub use const_::*; diff --git a/input/src/leo-input.pest b/input/src/leo-input.pest index f4c5ac0bdf..5981ddf903 100644 --- a/input/src/leo-input.pest +++ b/input/src/leo-input.pest @@ -218,8 +218,11 @@ header = { main | record | registers | state_leaf | state | identifier } /// Definitions +// Declared in definition/const_modifier.rs +const_ = { "const" } + // Declared in definition/definition.rs -definition = { parameter ~ "=" ~ expression ~ LINE_END } +definition = { const_? ~ parameter ~ "=" ~ expression ~ LINE_END } /// Table