mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-11-23 15:15:47 +03:00
Merge pull request #761 from AleoHQ/feature/const-inputs
[Feature, Compiler] Adds constant inputs
This commit is contained in:
commit
46220aa889
@ -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),
|
||||
|
@ -94,12 +94,18 @@ impl Input {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns the main function input value with the given `name`
|
||||
/// Returns the main function input value with the given `name`.
|
||||
#[allow(clippy::ptr_arg)]
|
||||
pub fn get(&self, name: &String) -> Option<Option<InputValue>> {
|
||||
self.program_input.get(name)
|
||||
}
|
||||
|
||||
/// Returns the constant input value with the given `name`.
|
||||
#[allow(clippy::ptr_arg)]
|
||||
pub fn get_constant(&self, name: &String) -> Option<Option<InputValue>> {
|
||||
self.program_input.get_constant(name)
|
||||
}
|
||||
|
||||
/// Returns the runtime register input values
|
||||
pub fn get_registers(&self) -> &Registers {
|
||||
self.program_input.get_registers()
|
||||
|
@ -14,11 +14,13 @@
|
||||
// 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/>.
|
||||
|
||||
/// Constructs an input section to store data parsed from a Leo input file.
|
||||
/// Constructs sections that pass variables to the main function through the input keyword.
|
||||
#[macro_export]
|
||||
macro_rules! input_section_impl {
|
||||
macro_rules! record_input_section {
|
||||
($($name: ident), *) => ($(
|
||||
|
||||
/// An input section declared in an input file with `[$name]`
|
||||
/// An input section declared in an input file with `[$name]`.
|
||||
#[derive(Clone, PartialEq, Eq, Default)]
|
||||
pub struct $name {
|
||||
is_present: bool,
|
||||
@ -63,10 +65,68 @@ macro_rules! input_section_impl {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns this section's [IndexMap] of values
|
||||
/// Returns this section's [IndexMap] of values.
|
||||
pub fn values(&self) -> IndexMap<Parameter, Option<InputValue>> {
|
||||
self.values.clone()
|
||||
}
|
||||
}
|
||||
)*)
|
||||
}
|
||||
|
||||
/// Constructs an input section to store data parsed from a Leo input file.
|
||||
/// Constructs sections that pass variables directly to the main function.
|
||||
#[macro_export]
|
||||
macro_rules! main_input_section {
|
||||
($($name: ident), *) => ($(
|
||||
|
||||
/// `[$name]` program input section.
|
||||
#[derive(Clone, PartialEq, Eq, Default)]
|
||||
pub struct $name {
|
||||
input: IndexMap<String, Option<InputValue>>,
|
||||
}
|
||||
|
||||
#[allow(clippy::len_without_is_empty)]
|
||||
impl $name {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Returns an empty version of this struct with `None` values.
|
||||
/// Called during constraint synthesis to provide private input variables.
|
||||
pub fn empty(&self) -> Self {
|
||||
let mut input = self.input.clone();
|
||||
|
||||
input.iter_mut().for_each(|(_name, value)| {
|
||||
*value = None;
|
||||
});
|
||||
|
||||
Self { input }
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.input.len()
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, key: String, value: Option<InputValue>) {
|
||||
self.input.insert(key, value);
|
||||
}
|
||||
|
||||
/// Parses main input definitions and stores them in `self`.
|
||||
pub fn parse(&mut self, definitions: Vec<Definition>) -> Result<(), InputParserError> {
|
||||
for definition in definitions {
|
||||
let name = definition.parameter.variable.value;
|
||||
let value = InputValue::from_expression(definition.parameter.type_, definition.expression)?;
|
||||
|
||||
self.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()
|
||||
}
|
||||
}
|
||||
)*)
|
||||
}
|
||||
|
22
ast/src/input/program_input/constant_input.rs
Normal file
22
ast/src/input/program_input/constant_input.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// 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::InputValue;
|
||||
use leo_input::{definitions::Definition, InputParserError};
|
||||
|
||||
use indexmap::IndexMap;
|
||||
|
||||
main_input_section!(ConstantInput);
|
@ -19,51 +19,4 @@ use leo_input::{definitions::Definition, InputParserError};
|
||||
|
||||
use indexmap::IndexMap;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Default)]
|
||||
pub struct MainInput {
|
||||
input: IndexMap<String, Option<InputValue>>,
|
||||
}
|
||||
|
||||
#[allow(clippy::len_without_is_empty)]
|
||||
impl MainInput {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Returns an empty version of this struct with `None` values.
|
||||
/// Called during constraint synthesis to provide private input variables.
|
||||
pub fn empty(&self) -> Self {
|
||||
let mut input = self.input.clone();
|
||||
|
||||
input.iter_mut().for_each(|(_name, value)| {
|
||||
*value = None;
|
||||
});
|
||||
|
||||
Self { input }
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.input.len()
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, key: String, value: Option<InputValue>) {
|
||||
self.input.insert(key, value);
|
||||
}
|
||||
|
||||
/// Parses main input definitions and stores them in `self`.
|
||||
pub fn parse(&mut self, definitions: Vec<Definition>) -> Result<(), InputParserError> {
|
||||
for definition in definitions {
|
||||
let name = definition.parameter.variable.value;
|
||||
let value = InputValue::from_expression(definition.parameter.type_, definition.expression)?;
|
||||
|
||||
self.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()
|
||||
}
|
||||
}
|
||||
main_input_section!(MainInput);
|
||||
|
@ -16,6 +16,9 @@
|
||||
|
||||
#![allow(clippy::module_inception)]
|
||||
|
||||
pub mod constant_input;
|
||||
pub use constant_input::*;
|
||||
|
||||
pub mod main_input;
|
||||
pub use main_input::*;
|
||||
|
||||
|
@ -14,7 +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 crate::{InputValue, MainInput, Registers};
|
||||
use crate::{ConstantInput, InputValue, MainInput, Registers};
|
||||
use leo_input::{
|
||||
sections::{Header, Section},
|
||||
InputParserError,
|
||||
@ -23,6 +23,7 @@ use leo_input::{
|
||||
#[derive(Clone, PartialEq, Eq, Default)]
|
||||
pub struct ProgramInput {
|
||||
pub main: MainInput,
|
||||
pub constants: ConstantInput,
|
||||
registers: Registers,
|
||||
}
|
||||
|
||||
@ -36,18 +37,24 @@ impl ProgramInput {
|
||||
/// Called during constraint synthesis to provide private input values.
|
||||
pub fn empty(&self) -> Self {
|
||||
let main = self.main.empty();
|
||||
let constants = self.constants.empty();
|
||||
let registers = self.registers.empty();
|
||||
|
||||
Self { main, registers }
|
||||
Self {
|
||||
main,
|
||||
constants,
|
||||
registers,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
let mut len = 0;
|
||||
|
||||
// add main input variables
|
||||
// Add main input variables and constants.
|
||||
len += self.main.len();
|
||||
len += self.constants.len();
|
||||
|
||||
// add registers
|
||||
// Add registers.
|
||||
if self.registers.is_present() {
|
||||
len += 1;
|
||||
}
|
||||
@ -58,6 +65,7 @@ impl ProgramInput {
|
||||
/// Parse each input included in a file and store them in `self`.
|
||||
pub fn parse(&mut self, section: Section) -> Result<(), InputParserError> {
|
||||
match section.header {
|
||||
Header::Constants(_constants) => self.constants.parse(section.definitions),
|
||||
Header::Main(_main) => self.main.parse(section.definitions),
|
||||
Header::Registers(_registers) => self.registers.parse(section.definitions),
|
||||
header => Err(InputParserError::input_section_header(header)),
|
||||
@ -70,6 +78,11 @@ impl ProgramInput {
|
||||
self.main.get(name)
|
||||
}
|
||||
|
||||
#[allow(clippy::ptr_arg)]
|
||||
pub fn get_constant(&self, name: &String) -> Option<Option<InputValue>> {
|
||||
self.constants.get(name)
|
||||
}
|
||||
|
||||
/// Returns the runtime register input values
|
||||
pub fn get_registers(&self) -> &Registers {
|
||||
&self.registers
|
||||
|
@ -19,4 +19,4 @@ use leo_input::{definitions::Definition, InputParserError};
|
||||
|
||||
use indexmap::IndexMap;
|
||||
|
||||
input_section_impl!(Registers);
|
||||
record_input_section!(Registers);
|
||||
|
@ -19,4 +19,4 @@ use leo_input::{definitions::Definition, InputParserError};
|
||||
|
||||
use indexmap::IndexMap;
|
||||
|
||||
input_section_impl!(Record);
|
||||
record_input_section!(Record);
|
||||
|
@ -19,4 +19,4 @@ use leo_input::{definitions::Definition, InputParserError};
|
||||
|
||||
use indexmap::IndexMap;
|
||||
|
||||
input_section_impl!(StateLeaf);
|
||||
record_input_section!(StateLeaf);
|
||||
|
@ -19,4 +19,4 @@ use leo_input::{definitions::Definition, InputParserError};
|
||||
|
||||
use indexmap::IndexMap;
|
||||
|
||||
input_section_impl!(State);
|
||||
record_input_section!(State);
|
||||
|
@ -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,
|
||||
|
@ -103,6 +103,33 @@ impl FunctionError {
|
||||
FunctionError::Error(FormattedError::new_from_span(message, span))
|
||||
}
|
||||
|
||||
pub fn input_type_mismatch(expected: String, actual: String, variable: String, span: &Span) -> Self {
|
||||
let message = format!(
|
||||
"Expected input variable `{}` to be type `{}`, found type `{}`",
|
||||
variable, expected, actual
|
||||
);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn expected_const_input(variable: String, span: &Span) -> Self {
|
||||
let message = format!(
|
||||
"Expected input variable `{}` to be constant. Move input variable `{}` to [constants] section of input file",
|
||||
variable, variable
|
||||
);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn expected_non_const_input(variable: String, span: &Span) -> Self {
|
||||
let message = format!(
|
||||
"Expected input variable `{}` to be non-constant. Move input variable `{}` to [main] section of input file",
|
||||
variable, variable
|
||||
);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn invalid_array(actual: String, span: &Span) -> Self {
|
||||
let message = format!("Expected function input array, found `{}`", actual);
|
||||
|
||||
@ -118,6 +145,15 @@ impl FunctionError {
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn tuple_size_mismatch(expected: usize, actual: usize, span: &Span) -> Self {
|
||||
let message = format!(
|
||||
"Input tuple size mismatch expected {}, found tuple with length {}",
|
||||
expected, actual
|
||||
);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn invalid_tuple(actual: String, span: &Span) -> Self {
|
||||
let message = format!("Expected function input tuple, found `{}`", actual);
|
||||
|
||||
@ -141,4 +177,10 @@ impl FunctionError {
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn double_input_declaration(input_name: String, span: &Span) -> Self {
|
||||
let message = format!("Input variable {} declared twice", input_name);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -26,13 +26,15 @@ use crate::{
|
||||
group::input::group_from_input,
|
||||
ConstrainedValue,
|
||||
},
|
||||
FieldType,
|
||||
GroupType,
|
||||
Integer,
|
||||
};
|
||||
|
||||
use leo_asg::Type;
|
||||
use leo_asg::{ConstInt, Type};
|
||||
use leo_ast::{InputValue, Span};
|
||||
|
||||
use snarkvm_fields::PrimeField;
|
||||
use snarkvm_gadgets::traits::utilities::boolean::Boolean;
|
||||
use snarkvm_r1cs::ConstraintSystem;
|
||||
|
||||
impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
|
||||
@ -58,7 +60,68 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
|
||||
)?)),
|
||||
Type::Array(type_, len) => self.allocate_array(cs, name, &*type_, *len, input_option, span),
|
||||
Type::Tuple(types) => self.allocate_tuple(cs, &name, types, input_option, span),
|
||||
_ => unimplemented!("main function input not implemented for type"),
|
||||
_ => unimplemented!("main function input not implemented for type {}", type_), // Should not happen.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Process constant inputs and return ConstrainedValue with constant value in it.
|
||||
impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
|
||||
pub fn constant_main_function_input<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
_cs: &mut CS,
|
||||
type_: &Type,
|
||||
name: &str,
|
||||
input_option: Option<InputValue>,
|
||||
span: &Span,
|
||||
) -> Result<ConstrainedValue<'a, F, G>, FunctionError> {
|
||||
let input = input_option.ok_or_else(|| FunctionError::input_not_found(name.to_string(), span))?;
|
||||
|
||||
match (type_, input) {
|
||||
(Type::Address, InputValue::Address(addr)) => Ok(ConstrainedValue::Address(Address::constant(addr, span)?)),
|
||||
(Type::Boolean, InputValue::Boolean(value)) => Ok(ConstrainedValue::Boolean(Boolean::constant(value))),
|
||||
(Type::Field, InputValue::Field(value)) => Ok(ConstrainedValue::Field(FieldType::constant(value, span)?)),
|
||||
(Type::Group, InputValue::Group(value)) => Ok(ConstrainedValue::Group(G::constant(&value.into(), span)?)),
|
||||
(Type::Integer(integer_type), InputValue::Integer(_, value)) => Ok(ConstrainedValue::Integer(
|
||||
Integer::new(&ConstInt::parse(integer_type, &value, span)?),
|
||||
)),
|
||||
(Type::Array(type_, arr_len), InputValue::Array(values)) => {
|
||||
if *arr_len != values.len() {
|
||||
return Err(FunctionError::invalid_input_array_dimensions(
|
||||
*arr_len,
|
||||
values.len(),
|
||||
span,
|
||||
));
|
||||
}
|
||||
|
||||
Ok(ConstrainedValue::Array(
|
||||
values
|
||||
.iter()
|
||||
.map(|x| self.constant_main_function_input(_cs, type_, name, Some(x.clone()), span))
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
))
|
||||
}
|
||||
(Type::Tuple(types), InputValue::Tuple(values)) => {
|
||||
if values.len() != types.len() {
|
||||
return Err(FunctionError::tuple_size_mismatch(types.len(), values.len(), span));
|
||||
}
|
||||
|
||||
Ok(ConstrainedValue::Tuple(
|
||||
values
|
||||
.iter()
|
||||
.map(|x| self.constant_main_function_input(_cs, type_, name, Some(x.clone()), span))
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
))
|
||||
}
|
||||
(Type::Circuit(_), _) => unimplemented!("main function input not implemented for type {}", type_), // Should not happen.
|
||||
|
||||
// Return an error if the input type and input value do not match.
|
||||
(_, input) => Err(FunctionError::input_type_mismatch(
|
||||
type_.to_string(),
|
||||
input.to_string(),
|
||||
name.to_string(),
|
||||
span,
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,11 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
|
||||
|
||||
match input_value {
|
||||
Some(InputValue::Tuple(values)) => {
|
||||
// Allocate each value in the tuple
|
||||
if values.len() != types.len() {
|
||||
return Err(FunctionError::tuple_size_mismatch(types.len(), values.len(), span));
|
||||
}
|
||||
|
||||
// Allocate each value in the tuple.
|
||||
for (i, (value, type_)) in values.into_iter().zip(types.iter()).enumerate() {
|
||||
let value_name = format!("{}_{}", &name, &i.to_string());
|
||||
|
||||
|
@ -61,18 +61,55 @@ 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(|| {
|
||||
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(),
|
||||
)?;
|
||||
|
||||
// Store a new variable for every allocated main function input
|
||||
let input_value = match (input_variable.const_, input.get(&name), input.get_constant(&name)) {
|
||||
// If variable is in both [main] and [constants] sections - error.
|
||||
(_, Some(_), Some(_)) => {
|
||||
return Err(FunctionError::double_input_declaration(
|
||||
name.clone(),
|
||||
&function.span.clone().unwrap_or_default(),
|
||||
));
|
||||
}
|
||||
// If input option is found in [main] section and input is not const.
|
||||
(false, Some(input_option), _) => self.allocate_main_function_input(
|
||||
cs,
|
||||
&input_variable.type_.clone(),
|
||||
&name,
|
||||
input_option,
|
||||
&function.span.clone().unwrap_or_default(),
|
||||
)?,
|
||||
// If input option is found in [constants] section and function argument is const.
|
||||
(true, _, Some(input_option)) => self.constant_main_function_input(
|
||||
cs,
|
||||
&input_variable.type_.clone(),
|
||||
&name,
|
||||
input_option,
|
||||
&function.span.clone().unwrap_or_default(),
|
||||
)?,
|
||||
// Function argument is const, input is not.
|
||||
(true, Some(_), None) => {
|
||||
return Err(FunctionError::expected_const_input(
|
||||
name.clone(),
|
||||
&function.span.clone().unwrap_or_default(),
|
||||
));
|
||||
}
|
||||
// Input is const, function argument is not.
|
||||
(false, None, Some(_)) => {
|
||||
return Err(FunctionError::expected_non_const_input(
|
||||
name.clone(),
|
||||
&function.span.clone().unwrap_or_default(),
|
||||
));
|
||||
}
|
||||
// When not found - Error out.
|
||||
(_, _, _) => {
|
||||
return Err(FunctionError::input_not_found(
|
||||
name.clone(),
|
||||
&function.span.clone().unwrap_or_default(),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
// Store a new variable for every function input.
|
||||
self.store(input_variable.id, input_value);
|
||||
}
|
||||
arguments.push(Cell::new(&*function.scope.alloc_expression(Expression::VariableRef(
|
||||
|
@ -16,5 +16,6 @@
|
||||
|
||||
mod program_input;
|
||||
mod program_input_and_program_state;
|
||||
mod program_input_constants;
|
||||
mod program_registers;
|
||||
mod program_state;
|
||||
|
@ -0,0 +1,2 @@
|
||||
[main]
|
||||
x: (u8, bool) = (10, true); // wrong size here; main expects (u8, bool, u8)
|
@ -0,0 +1,3 @@
|
||||
function main(x: (u8, bool, u8)) {
|
||||
console.log("x: {}", x);
|
||||
}
|
@ -94,6 +94,16 @@ fn test_input_array_dimensions_mismatch() {
|
||||
expect_fail(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tuple_size_mismatch() {
|
||||
let program_string = include_str!("main_tuple_fail.leo");
|
||||
let input_string = include_str!("input/main_tuple_fail.in");
|
||||
|
||||
let program = parse_program_with_input(program_string, input_string).unwrap();
|
||||
|
||||
expect_fail(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_field_input() {
|
||||
let program_string = include_str!("main_field.leo");
|
||||
|
@ -0,0 +1,2 @@
|
||||
[constants]
|
||||
a: bool = true;
|
@ -0,0 +1,2 @@
|
||||
[constants]
|
||||
x: [i16; 1] = [0i16; 1];
|
@ -0,0 +1,2 @@
|
||||
[constants]
|
||||
x: [i16; 1] = [0i16; 1];
|
@ -0,0 +1,5 @@
|
||||
[main]
|
||||
a: bool = true;
|
||||
|
||||
[constants]
|
||||
a: bool = false;
|
@ -0,0 +1,2 @@
|
||||
[constants]
|
||||
bad_name: bool = true;
|
@ -0,0 +1,2 @@
|
||||
[constants]
|
||||
a: u8 = 1;
|
@ -0,0 +1,3 @@
|
||||
[constants]
|
||||
a: field = 1;
|
||||
b: field = -1;
|
@ -0,0 +1,4 @@
|
||||
[constants]
|
||||
a: group = 1group;
|
||||
b: group = -1group;
|
||||
c: group = (0, -1)group;
|
@ -0,0 +1,2 @@
|
||||
[constants]
|
||||
x: [i16; (2, 2, 3)] = [0i16; (2, 2, 3)];
|
@ -0,0 +1,3 @@
|
||||
[constants]
|
||||
a: bool = true;
|
||||
b: bool = false;
|
@ -0,0 +1,2 @@
|
||||
[main]
|
||||
a: bool = true; // expecting const a, not main a
|
@ -0,0 +1,2 @@
|
||||
[constants]
|
||||
x: (u8, bool) = (10, true); // wrong size here; main expects (u8, bool, u8)
|
@ -0,0 +1,2 @@
|
||||
[constants]
|
||||
a: u8 = 10;
|
@ -0,0 +1,3 @@
|
||||
function main(const a: bool) {
|
||||
console.assert(a == true);
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
function main (const x: [i16; 1]) {
|
||||
console.log("{}", x);
|
||||
console.assert(x[0] == 0);
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
function main(const x: [i16; 2]){
|
||||
console.log("x: {}", x);
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
function main(const a: field, const b: field) {
|
||||
// Change to assert when == is implemented for field.
|
||||
console.log("a: {}", a);
|
||||
console.log("b: {}", b);
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
function main(const a: group, const b: group, const c: group) {
|
||||
// Change to assert when == is implemented for group.
|
||||
console.log("a: {}", a);
|
||||
console.log("b: {}", b);
|
||||
console.log("c: {}", c);
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
function main(const x: [i16; (2, 2, 3)]){
|
||||
console.log("x: {}", x);
|
||||
|
||||
let y: [i16; (2, 2, 3)] = [0i16; (2, 2, 3)];
|
||||
console.log("y: {}", y);
|
||||
|
||||
console.assert(x[0][0][0] == y[0][0][0]);
|
||||
console.assert(x[1][1][2] == y[1][1][2]);
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
function main(const a: bool, const b: bool) {
|
||||
console.assert(a == true);
|
||||
console.assert(b == false);
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
function main(const x: (u8, bool, u8)) {
|
||||
console.log("x: {}", x);
|
||||
}
|
145
compiler/tests/input_files/program_input_constants/mod.rs
Normal file
145
compiler/tests/input_files/program_input_constants/mod.rs
Normal file
@ -0,0 +1,145 @@
|
||||
// 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::{assert_satisfied, expect_compiler_error, parse_program_with_input, EdwardsTestCompiler};
|
||||
use leo_compiler::errors::CompilerError;
|
||||
|
||||
fn expect_fail(program: EdwardsTestCompiler) {
|
||||
match expect_compiler_error(program) {
|
||||
CompilerError::FunctionError(_) => {}
|
||||
err => panic!("expected input parser error, got {:?}", err),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_input_pass() {
|
||||
let program_string = include_str!("main.leo");
|
||||
let input_string = include_str!("input/main.in");
|
||||
|
||||
let program = parse_program_with_input(program_string, input_string).unwrap();
|
||||
|
||||
assert_satisfied(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_input_array_fail() {
|
||||
let program_string = include_str!("main_array.leo");
|
||||
let input_string = include_str!("input/main_array.in");
|
||||
|
||||
let program = parse_program_with_input(program_string, input_string).unwrap();
|
||||
|
||||
assert_satisfied(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_input_multi_dimension_array() {
|
||||
let program_string = include_str!("main_multi_dimension_array.leo");
|
||||
let input_string = include_str!("input/main_multi_dimension_array.in");
|
||||
|
||||
let program = parse_program_with_input(program_string, input_string).unwrap();
|
||||
|
||||
assert_satisfied(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_input_fail_name() {
|
||||
let program_string = include_str!("main.leo");
|
||||
let input_string = include_str!("input/main_fail_name.in");
|
||||
|
||||
let program = parse_program_with_input(program_string, input_string).unwrap();
|
||||
|
||||
expect_fail(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_input_fail_type() {
|
||||
let program_string = include_str!("main.leo");
|
||||
let input_string = include_str!("input/main_fail_type.in");
|
||||
|
||||
let program = parse_program_with_input(program_string, input_string).unwrap();
|
||||
|
||||
expect_fail(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_input_multiple() {
|
||||
let program_string = include_str!("main_multiple.leo");
|
||||
let input_string = include_str!("input/main_multiple.in");
|
||||
|
||||
let program = parse_program_with_input(program_string, input_string).unwrap();
|
||||
|
||||
assert_satisfied(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_input_array_dimensions_mismatch() {
|
||||
let program_string = include_str!("main_array_fail.leo");
|
||||
let input_string = include_str!("input/main_array_fail.in");
|
||||
|
||||
let program = parse_program_with_input(program_string, input_string).unwrap();
|
||||
|
||||
expect_fail(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_input_double_declaration() {
|
||||
let program_string = include_str!("main.leo");
|
||||
let input_string = include_str!("input/main_double_declaration_fail.in");
|
||||
|
||||
let program = parse_program_with_input(program_string, input_string).unwrap();
|
||||
|
||||
expect_fail(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_non_constant_input() {
|
||||
let program_string = include_str!("main.leo");
|
||||
let input_string = include_str!("input/main_not_const_input_fail.in");
|
||||
|
||||
let program = parse_program_with_input(program_string, input_string).unwrap();
|
||||
|
||||
expect_fail(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tuple_size_mismatch() {
|
||||
let program_string = include_str!("main_tuple_fail.leo");
|
||||
let input_string = include_str!("input/main_tuple_fail.in");
|
||||
|
||||
let program = parse_program_with_input(program_string, input_string).unwrap();
|
||||
|
||||
expect_fail(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_field_input() {
|
||||
let program_string = include_str!("main_field.leo");
|
||||
let input_string = include_str!("input/main_field.in");
|
||||
|
||||
let program = parse_program_with_input(program_string, input_string).unwrap();
|
||||
|
||||
assert_satisfied(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_group_input() {
|
||||
let program_string = include_str!("main_group.leo");
|
||||
let input_string = include_str!("input/main_group.in");
|
||||
|
||||
let program = parse_program_with_input(program_string, input_string).unwrap();
|
||||
|
||||
assert_satisfied(program);
|
||||
}
|
@ -1,4 +1,8 @@
|
||||
[main]
|
||||
hash_input: [bool; 256] = [true; 256];
|
||||
|
||||
[constants]
|
||||
parameters: [group; 256] = [1group; 256];
|
||||
|
||||
[registers]
|
||||
r0: group = (1, 0)group;
|
@ -18,10 +18,8 @@ circuit PedersenHash {
|
||||
}
|
||||
|
||||
// The 'pedersen-hash' main function.
|
||||
function main() -> group {
|
||||
let parameters = [1group; 256];
|
||||
function main(hash_input: [bool; 256], const parameters: [group; 256]) -> group {
|
||||
let pedersen = PedersenHash::new(parameters);
|
||||
let hash_input: [bool; 256] = [true; 256];
|
||||
return pedersen.hash(hash_input)
|
||||
}
|
||||
|
||||
|
@ -210,11 +210,14 @@ registers = { "registers" }
|
||||
// Declared in sections/state.rs
|
||||
state = { "state" }
|
||||
|
||||
// Declared in sections/constants.rs
|
||||
constants = { "constants" }
|
||||
|
||||
// Declared in sections/state_leaf.rs
|
||||
state_leaf = { "state_leaf" }
|
||||
|
||||
// Declared in sections/header.rs
|
||||
header = { main | record | registers | state_leaf | state | identifier }
|
||||
header = { main | constants | record | registers | state_leaf | state | identifier }
|
||||
|
||||
/// Definitions
|
||||
|
||||
|
27
input/src/sections/constants.rs
Normal file
27
input/src/sections/constants.rs
Normal 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::constants))]
|
||||
pub struct Constants<'ast> {
|
||||
#[pest_ast(outer())]
|
||||
pub span: Span<'ast>,
|
||||
}
|
@ -17,7 +17,7 @@
|
||||
use crate::{
|
||||
ast::Rule,
|
||||
common::Identifier,
|
||||
sections::{Main, Record, Registers, State, StateLeaf},
|
||||
sections::{Constants, Main, Record, Registers, State, StateLeaf},
|
||||
};
|
||||
|
||||
use pest::Span;
|
||||
@ -27,6 +27,7 @@ use std::fmt;
|
||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||
#[pest_ast(rule(Rule::header))]
|
||||
pub enum Header<'ast> {
|
||||
Constants(Constants<'ast>),
|
||||
Main(Main<'ast>),
|
||||
Record(Record<'ast>),
|
||||
Registers(Registers<'ast>),
|
||||
@ -38,6 +39,7 @@ pub enum Header<'ast> {
|
||||
impl<'ast> Header<'ast> {
|
||||
pub fn span(self) -> Span<'ast> {
|
||||
match self {
|
||||
Header::Constants(constants) => constants.span,
|
||||
Header::Main(main) => main.span,
|
||||
Header::Record(record) => record.span,
|
||||
Header::Registers(registers) => registers.span,
|
||||
@ -51,6 +53,7 @@ impl<'ast> Header<'ast> {
|
||||
impl<'ast> fmt::Display for Header<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Header::Constants(_constants) => write!(f, "constants"),
|
||||
Header::Main(_main) => write!(f, "main"),
|
||||
Header::Record(_record) => write!(f, "record"),
|
||||
Header::Registers(_registers) => write!(f, "registers"),
|
||||
|
@ -14,6 +14,9 @@
|
||||
// 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 constants;
|
||||
pub use constants::*;
|
||||
|
||||
pub mod header;
|
||||
pub use header::*;
|
||||
|
||||
|
@ -113,19 +113,20 @@ impl<E: PairingEngine> ConstraintSystem<E::Fr> for CircuitSynthesizer<E> {
|
||||
}
|
||||
|
||||
fn pop_namespace(&mut self) {
|
||||
if let Some(ns) = self.namespaces.pop() {
|
||||
for idx in ns.constraint_indices {
|
||||
self.constraints.remove(idx);
|
||||
}
|
||||
|
||||
for idx in ns.private_var_indices {
|
||||
self.private_variables.remove(idx);
|
||||
}
|
||||
|
||||
for idx in ns.public_var_indices {
|
||||
self.public_variables.remove(idx);
|
||||
}
|
||||
}
|
||||
// Todo @ljedrz: Fix constraint system optimizations.
|
||||
// if let Some(ns) = self.namespaces.pop() {
|
||||
// for idx in ns.constraint_indices {
|
||||
// self.constraints.remove(idx);
|
||||
// }
|
||||
//
|
||||
// for idx in ns.private_var_indices {
|
||||
// self.private_variables.remove(idx);
|
||||
// }
|
||||
//
|
||||
// for idx in ns.public_var_indices {
|
||||
// self.public_variables.remove(idx);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
fn get_root(&mut self) -> &mut Self::Root {
|
||||
|
Loading…
Reference in New Issue
Block a user