staging commit with const input syntax and constants processing

This commit is contained in:
damirka 2021-03-11 19:05:08 +03:00
parent c47ab84b1b
commit 47e4d23ab1
13 changed files with 153 additions and 26 deletions

View File

@ -91,6 +91,16 @@ pub enum GroupValue {
Tuple(GroupCoordinate, GroupCoordinate),
}
impl From<leo_ast::GroupValue> 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),

View File

@ -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<Option<InputValue>> {
pub fn get(&self, name: &String) -> Option<(Option<InputValue>, bool)> {
self.program_input.get(name)
}

View File

@ -22,6 +22,7 @@ use indexmap::IndexMap;
#[derive(Clone, PartialEq, Eq, Default)]
pub struct MainInput {
input: IndexMap<String, Option<InputValue>>,
constants: IndexMap<String, Option<InputValue>>,
}
#[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<InputValue>) {
@ -54,16 +60,27 @@ impl MainInput {
pub fn parse(&mut self, definitions: Vec<Definition>) -> 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<Option<InputValue>> {
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<InputValue>, 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,
}
}
}

View File

@ -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<Option<InputValue>> {
pub fn get(&self, name: &String) -> Option<(Option<InputValue>, bool)> {
self.main.get(name)
}

View File

@ -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,

View File

@ -172,7 +172,6 @@ impl<'a, F: PrimeField, G: GroupType<F>> 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(),

View File

@ -25,8 +25,5 @@ pub fn evaluate_bit_not<'a, F: PrimeField, G: GroupType<F>>(
value: ConstrainedValue<'a, F, G>,
span: &Span,
) -> Result<ConstrainedValue<'a, F, G>, 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))
}

View File

@ -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<F>> ConstrainedProgram<'a, F, G> {
pub fn allocate_main_function_input<CS: ConstraintSystem<F>>(
&mut self,
@ -62,3 +66,48 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
}
}
}
/// Process constant inputs and return ConstrainedValue with constant value in it.
impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
pub fn parse_constant_main_function_input<CS: ConstraintSystem<F>>(
&mut self,
// TODO: remove unnecessary arguments
_cs: &mut CS,
_type_: &Type,
name: &str,
input_option: Option<InputValue>,
span: &Span,
) -> Result<ConstrainedValue<'a, F, G>, 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::<u8>().unwrap()),
IntegerType::U16 => ConstInt::U16(value.parse::<u16>().unwrap()),
IntegerType::U32 => ConstInt::U32(value.parse::<u32>().unwrap()),
IntegerType::U64 => ConstInt::U64(value.parse::<u64>().unwrap()),
IntegerType::U128 => ConstInt::U128(value.parse::<u128>().unwrap()),
IntegerType::I8 => ConstInt::I8(value.parse::<i8>().unwrap()),
IntegerType::I16 => ConstInt::I16(value.parse::<i16>().unwrap()),
IntegerType::I32 => ConstInt::I32(value.parse::<i32>().unwrap()),
IntegerType::I64 => ConstInt::I64(value.parse::<i64>().unwrap()),
IntegerType::I128 => ConstInt::I128(value.parse::<i128>().unwrap()),
};
ConstrainedValue::Integer(Integer::new(&const_int))
}
// TODO: array and tuple values.
// InputValue::Array(Vec<InputValue>) => ,
// InputValue::Tuple(Vec<InputValue>),
// TODO: rework this error to something better fitting into context.
_ => return Err(FunctionError::input_not_found(name.to_string(), span)),
})
}
}

View File

@ -61,16 +61,28 @@ impl<'a, F: PrimeField, G: GroupType<F>> 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);

View File

@ -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 <https://www.gnu.org/licenses/>.
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>,
}

View File

@ -14,6 +14,7 @@
// 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 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<Const<'ast>>,
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()
}
}

View File

@ -16,3 +16,6 @@
pub mod definition;
pub use definition::*;
pub mod const_;
pub use const_::*;

View File

@ -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