impl mutable variable type

This commit is contained in:
collin 2020-05-13 15:19:25 -07:00
parent 87e8e67967
commit 3b263d7cc9
21 changed files with 369 additions and 349 deletions

View File

@ -352,28 +352,24 @@ pub struct Mutable {}
pub struct Variable<'ast> {
pub mutable: Option<Mutable>,
pub identifier: Identifier<'ast>,
pub _type: Option<Type<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for Variable<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.identifier)
}
}
if let Some(ref _mutable) = self.mutable {
write!(f, "mut ")?;
}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::optionally_typed_variable))]
pub struct OptionallyTypedVariable<'ast> {
pub _type: Option<Type<'ast>>,
pub variable: Variable<'ast>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
write!(f, "{}", self.identifier)?;
impl<'ast> fmt::Display for OptionallyTypedVariable<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.variable)
if let Some(ref _type) = self._type {
write!(f, ": {}", _type)?;
}
write!(f, "")
}
}
@ -725,9 +721,11 @@ impl<'ast> fmt::Display for Expression<'ast> {
Expression::ArrayInitializer(ref expression) => {
write!(f, "[{} ; {}]", expression.expression, expression.count)
}
Expression::CircuitInline(ref expression) => {
write!(f, "inline circuit display not impl {}", expression.identifier)
}
Expression::CircuitInline(ref expression) => write!(
f,
"inline circuit display not impl {}",
expression.identifier
),
Expression::Postfix(ref expression) => {
write!(f, "Postfix display not impl {}", expression.identifier)
}
@ -928,7 +926,7 @@ pub struct ForStatement<'ast> {
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::statement_multiple_assignment))]
pub struct MultipleAssignmentStatement<'ast> {
pub assignees: Vec<OptionallyTypedVariable<'ast>>,
pub variables: Vec<Variable<'ast>>,
pub function_name: Identifier<'ast>,
pub arguments: Vec<Expression<'ast>>,
#[pest_ast(outer())]
@ -939,7 +937,6 @@ pub struct MultipleAssignmentStatement<'ast> {
#[pest_ast(rule(Rule::statement_definition))]
pub struct DefinitionStatement<'ast> {
pub variable: Variable<'ast>,
pub _type: Option<Type<'ast>>,
pub expression: Expression<'ast>,
#[pest_ast(outer())]
pub span: Span<'ast>,
@ -1037,9 +1034,9 @@ impl<'ast> fmt::Display for ForStatement<'ast> {
impl<'ast> fmt::Display for MultipleAssignmentStatement<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for (i, id) in self.assignees.iter().enumerate() {
for (i, id) in self.variables.iter().enumerate() {
write!(f, "{}", id)?;
if i < self.assignees.len() - 1 {
if i < self.variables.len() - 1 {
write!(f, ", ")?;
}
}
@ -1049,14 +1046,7 @@ impl<'ast> fmt::Display for MultipleAssignmentStatement<'ast> {
impl<'ast> fmt::Display for DefinitionStatement<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self._type {
Some(ref _type) => write!(
f,
"let {} : {} = {};",
self.variable, _type, self.expression
),
None => write!(f, "let {} = {}", self.variable, self.expression),
}
write!(f, "let {} = {};", self.variable, self.expression)
}
}
@ -1094,9 +1084,10 @@ impl<'ast> fmt::Display for Statement<'ast> {
// Functions
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::parameter))]
pub struct Parameter<'ast> {
pub variable: Variable<'ast>,
#[pest_ast(rule(Rule::input_model))]
pub struct InputModel<'ast> {
pub mutable: Option<Mutable>,
pub identifier: Identifier<'ast>,
pub visibility: Option<Visibility>,
pub _type: Type<'ast>,
#[pest_ast(outer())]
@ -1107,7 +1098,7 @@ pub struct Parameter<'ast> {
#[pest_ast(rule(Rule::function_definition))]
pub struct Function<'ast> {
pub function_name: Identifier<'ast>,
pub parameters: Vec<Parameter<'ast>>,
pub parameters: Vec<InputModel<'ast>>,
pub returns: Vec<Type<'ast>>,
pub statements: Vec<Statement<'ast>>,
#[pest_ast(outer())]
@ -1155,7 +1146,7 @@ pub struct Import<'ast> {
#[pest_ast(rule(Rule::file))]
pub struct File<'ast> {
pub imports: Vec<Import<'ast>>,
pub circuits : Vec<Circuit<'ast>>,
pub circuits: Vec<Circuit<'ast>>,
pub functions: Vec<Function<'ast>>,
pub eoi: EOI,
#[pest_ast(outer())]

View File

@ -3,7 +3,7 @@
use crate::{
constraints::{ConstrainedProgram, ConstrainedValue},
errors::BooleanError,
types::{InputModel, InputValue},
types::InputValue,
};
use snarkos_errors::gadgets::SynthesisError;
@ -19,7 +19,8 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
pub(crate) fn bool_from_input(
&mut self,
cs: &mut CS,
input_model: InputModel<F, G>,
name: String,
private: bool,
input_value: Option<InputValue<F, G>>,
) -> Result<ConstrainedValue<F, G>, BooleanError> {
// Check that the input value is the correct type
@ -35,8 +36,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
};
// Check visibility of input
let name = input_model.variable.name.clone();
let number = if input_model.private {
let number = if private {
Boolean::alloc(cs.ns(|| name), || {
bool_value.ok_or(SynthesisError::AssignmentMissing)
})?

View File

@ -6,7 +6,7 @@ use crate::{
ConstrainedProgram, ConstrainedValue,
},
errors::ExpressionError,
types::{CircuitMember, Expression, RangeOrExpression, SpreadOrExpression, Variable},
types::{CircuitMember, Expression, Identifier, RangeOrExpression, SpreadOrExpression},
};
use snarkos_models::{
@ -16,10 +16,10 @@ use snarkos_models::{
impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgram<F, G, CS> {
/// Enforce a variable expression by getting the resolved value
pub(crate) fn enforce_variable(
pub(crate) fn evaluate_identifier(
&mut self,
scope: String,
unresolved_variable: Variable<F, G>,
unresolved_variable: Identifier<F, G>,
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
// Evaluate the variable name in the current function scope
let variable_name = new_scope_from_variable(scope, &unresolved_variable);
@ -260,7 +260,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
for element in array.into_iter() {
match *element {
SpreadOrExpression::Spread(spread) => match spread {
Expression::Variable(variable) => {
Expression::Identifier(variable) => {
let array_name = new_scope_from_variable(function_scope.clone(), &variable);
match self.get(&array_name) {
Some(value) => match value {
@ -340,7 +340,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
cs: &mut CS,
file_scope: String,
function_scope: String,
variable: Variable<F, G>,
variable: Identifier<F, G>,
members: Vec<CircuitMember<F, G>>,
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
let circuit_name = new_variable_from_variable(file_scope.clone(), &variable);
@ -355,10 +355,10 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
.into_iter()
.zip(members.clone().into_iter())
{
if field.variable != member.variable {
if field.identifier != member.identifier {
return Err(ExpressionError::InvalidCircuitObject(
field.variable.name,
member.variable.name,
field.identifier.name,
member.identifier.name,
));
}
// Resolve and enforce circuit fields
@ -372,7 +372,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
// Check member types
member_value.expect_type(&field._type)?;
resolved_members.push(ConstrainedCircuitMember(member.variable, member_value))
resolved_members.push(ConstrainedCircuitMember(member.identifier, member_value))
}
Ok(ConstrainedValue::CircuitExpression(
@ -390,7 +390,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
file_scope: String,
function_scope: String,
circuit_variable: Box<Expression<F, G>>,
circuit_member: Variable<F, G>,
circuit_member: Identifier<F, G>,
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
match self.enforce_expression(cs, file_scope, function_scope, *circuit_variable)? {
ConstrainedValue::CircuitExpression(_name, members) => {
@ -413,7 +413,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
cs: &mut CS,
file_scope: String,
function_scope: String,
function: Variable<F, G>,
function: Identifier<F, G>,
arguments: Vec<Expression<F, G>>,
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
let function_name = new_variable_from_variable(file_scope.clone(), &function);
@ -444,8 +444,8 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
match expression {
// Variables
Expression::Variable(unresolved_variable) => {
self.enforce_variable(function_scope, unresolved_variable)
Expression::Identifier(unresolved_variable) => {
self.evaluate_identifier(function_scope, unresolved_variable)
}
// Values

View File

@ -3,7 +3,7 @@
use crate::{
constraints::{ConstrainedProgram, ConstrainedValue},
errors::FieldElementError,
types::{FieldElement, InputModel, InputValue, Integer},
types::{FieldElement, InputValue, Integer},
};
use snarkos_errors::gadgets::SynthesisError;
@ -16,7 +16,8 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
pub(crate) fn field_element_from_input(
&mut self,
cs: &mut CS,
input_model: InputModel<F, G>,
name: String,
private: bool,
input_value: Option<InputValue<F, G>>,
) -> Result<ConstrainedValue<F, G>, FieldElementError> {
// Check that the parameter value is the correct type
@ -32,8 +33,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
};
// Check visibility of parameter
let name = input_model.variable.name.clone();
let field_value = if input_model.private {
let field_value = if private {
cs.alloc(
|| name,
|| field_option.ok_or(SynthesisError::AssignmentMissing),

View File

@ -2,14 +2,9 @@
//! a resolved Leo program.
use crate::{
constraints::{
new_scope, new_scope_from_variable, new_variable_from_variables, ConstrainedProgram,
ConstrainedValue,
},
constraints::{new_scope, new_variable_from_variables, ConstrainedProgram, ConstrainedValue},
errors::{FunctionError, ImportError},
new_variable_from_variable,
types::{Expression, Function, InputValue, Program, Type},
InputModel, Variable,
types::{Expression, Function, Identifier, InputValue, Program, Type},
};
use snarkos_models::{
@ -36,7 +31,9 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
input: Expression<F, G>,
) -> Result<ConstrainedValue<F, G>, FunctionError> {
match input {
Expression::Variable(variable) => Ok(self.enforce_variable(caller_scope, variable)?),
Expression::Identifier(variable) => {
Ok(self.evaluate_identifier(caller_scope, variable)?)
}
expression => Ok(self.enforce_expression(cs, scope, function_name, expression)?),
}
}
@ -59,7 +56,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
function.inputs.clone().iter().zip(inputs.into_iter())
{
// First evaluate input expression
let input_value = self.enforce_input(
let mut input_value = self.enforce_input(
cs,
scope.clone(),
caller_scope.clone(),
@ -70,10 +67,14 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
// Check that input is correct type
input_value.expect_type(&input_model._type)?;
if input_model.mutable {
input_value = ConstrainedValue::Mutable(Box::new(input_value))
}
// Store input as variable with {function_name}_{input_name}
let variable_name =
new_scope_from_variable(function_name.clone(), &input_model.variable);
self.store(variable_name, input_value);
let input_program_identifier =
new_scope(function_name.clone(), input_model.identifier.name.clone());
self.store(input_program_identifier, input_value);
}
// Evaluate function statements
@ -99,8 +100,8 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
fn allocate_array(
&mut self,
cs: &mut CS,
array_name: Variable<F, G>,
array_private: bool,
name: String,
private: bool,
array_type: Type<F, G>,
array_dimensions: Vec<usize>,
input_value: Option<InputValue<F, G>>,
@ -115,18 +116,14 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
// Allocate each value in the current row
for (i, value) in arr.into_iter().enumerate() {
let array_input_model = InputModel {
private: array_private,
_type: array_type.next_dimension(&array_dimensions),
variable: new_variable_from_variables(
&array_name,
&Variable::new(i.to_string()),
),
};
let value_name = new_scope(name.clone(), i.to_string());
let value_type = array_type.next_dimension(&array_dimensions);
array_value.push(self.allocate_main_function_input(
cs,
array_input_model,
value_type,
value_name,
private,
Some(value),
)?)
}
@ -134,20 +131,14 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
None => {
// Allocate all row values as none
for i in 0..expected_length {
let array_input_model = InputModel {
private: array_private,
_type: array_type.next_dimension(&array_dimensions),
variable: new_variable_from_variables(
&array_name,
&Variable::new(i.to_string()),
),
};
let value_name = new_scope(name.clone(), i.to_string());
let value_type = array_type.next_dimension(&array_dimensions);
array_value.push(self.allocate_main_function_input(
cs,
array_input_model,
None,
)?);
array_value.push(
self.allocate_main_function_input(
cs, value_type, value_name, private, None,
)?,
);
}
}
_ => {
@ -163,25 +154,22 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
fn allocate_main_function_input(
&mut self,
cs: &mut CS,
input_model: InputModel<F, G>,
_type: Type<F, G>,
name: String,
private: bool,
input_value: Option<InputValue<F, G>>,
) -> Result<ConstrainedValue<F, G>, FunctionError> {
match input_model._type {
Type::IntegerType(ref _integer_type) => {
Ok(self.integer_from_parameter(cs, input_model, input_value)?)
match _type {
Type::IntegerType(integer_type) => {
Ok(self.integer_from_parameter(cs, integer_type, name, private, input_value)?)
}
Type::FieldElement => {
Ok(self.field_element_from_input(cs, input_model, input_value)?)
Ok(self.field_element_from_input(cs, name, private, input_value)?)
}
Type::Boolean => Ok(self.bool_from_input(cs, name, private, input_value)?),
Type::Array(_type, dimensions) => {
self.allocate_array(cs, name, private, *_type, dimensions, input_value)
}
Type::Boolean => Ok(self.bool_from_input(cs, input_model, input_value)?),
Type::Array(_type, dimensions) => self.allocate_array(
cs,
input_model.variable,
input_model.private,
*_type,
dimensions,
input_value,
),
_ => unimplemented!("main function input not implemented for type"),
}
}
@ -200,16 +188,26 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
// Iterate over main function inputs and allocate new passed-by variable values
let mut input_variables = vec![];
for (input_model, input_value) in
for (input_model, input_option) in
function.inputs.clone().into_iter().zip(inputs.into_iter())
{
let variable = new_variable_from_variable(scope.clone(), &input_model.variable);
let value = self.allocate_main_function_input(cs, input_model, input_value)?;
let input_name = new_scope(function_name.clone(), input_model.identifier.name.clone());
let mut input_value = self.allocate_main_function_input(
cs,
input_model._type,
input_name.clone(),
input_model.private,
input_option,
)?;
// store a new variable for every allocated main function input
self.store_variable(variable.clone(), value);
if input_model.mutable {
input_value = ConstrainedValue::Mutable(Box::new(input_value))
}
input_variables.push(Expression::Variable(variable));
// Store a new variable for every allocated main function input
self.store(input_name.clone(), input_value);
input_variables.push(Expression::Identifier(Identifier::new(input_name)));
}
self.enforce_function(cs, scope, function_name, function, input_variables)
@ -247,7 +245,8 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
.functions
.into_iter()
.for_each(|(function_name, function)| {
let resolved_function_name = new_scope(program_name.name.clone(), function_name.name);
let resolved_function_name =
new_scope(program_name.name.clone(), function_name.name);
self.store(resolved_function_name, ConstrainedValue::Function(function));
});

View File

@ -3,7 +3,7 @@
use crate::{
constraints::{ConstrainedProgram, ConstrainedValue},
errors::IntegerError,
types::{InputModel, InputValue, Integer, Type},
types::{InputValue, Integer},
IntegerType,
};
@ -41,35 +41,29 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
pub(crate) fn integer_from_parameter(
&mut self,
cs: &mut CS,
integer_model: InputModel<F, G>,
integer_type: IntegerType,
name: String,
private: bool,
integer_value: Option<InputValue<F, G>>,
) -> Result<ConstrainedValue<F, G>, IntegerError> {
let integer_type = match &integer_model._type {
Type::IntegerType(integer_type) => integer_type,
_type => return Err(IntegerError::InvalidType(_type.to_string())),
};
// Check that the parameter value is the correct type
// Check that the input value is the correct type
let integer_option = match integer_value {
Some(parameter) => {
if let InputValue::Integer(integer) = parameter {
Some(input) => {
if let InputValue::Integer(integer) = input {
Some(integer)
} else {
return Err(IntegerError::InvalidInteger(
integer_model._type.to_string(),
parameter.to_string(),
));
return Err(IntegerError::InvalidInteger(input.to_string()));
}
}
None => None,
};
match integer_type {
IntegerType::U8 => self.u8_from_input(cs, integer_model, integer_option),
IntegerType::U16 => self.u16_from_input(cs, integer_model, integer_option),
IntegerType::U32 => self.u32_from_input(cs, integer_model, integer_option),
IntegerType::U64 => self.u64_from_input(cs, integer_model, integer_option),
IntegerType::U128 => self.u128_from_integer(cs, integer_model, integer_option),
IntegerType::U8 => self.u8_from_input(cs, name, private, integer_option),
IntegerType::U16 => self.u16_from_input(cs, name, private, integer_option),
IntegerType::U32 => self.u32_from_input(cs, name, private, integer_option),
IntegerType::U64 => self.u64_from_input(cs, name, private, integer_option),
IntegerType::U128 => self.u128_from_input(cs, name, private, integer_option),
}
}

View File

@ -3,7 +3,7 @@
use crate::{
constraints::{ConstrainedProgram, ConstrainedValue},
errors::IntegerError,
types::{InputModel, Integer},
types::Integer,
};
use snarkos_errors::gadgets::SynthesisError;
@ -16,10 +16,11 @@ use snarkos_models::{
};
impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgram<F, G, CS> {
pub(crate) fn u128_from_integer(
pub(crate) fn u128_from_input(
&mut self,
cs: &mut CS,
parameter_model: InputModel<F, G>,
name: String,
private: bool,
integer_option: Option<usize>,
) -> Result<ConstrainedValue<F, G>, IntegerError> {
// Type cast to u128 in rust.
@ -27,8 +28,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
let u128_option = integer_option.map(|integer| integer as u128);
// Check visibility of parameter
let name = parameter_model.variable.name.clone();
let integer_value = if parameter_model.private {
let integer_value = if private {
UInt128::alloc(cs.ns(|| name), || {
u128_option.ok_or(SynthesisError::AssignmentMissing)
})?

View File

@ -3,7 +3,7 @@
use crate::{
constraints::{ConstrainedProgram, ConstrainedValue},
errors::IntegerError,
types::{InputModel, Integer},
types::Integer,
};
use snarkos_errors::gadgets::SynthesisError;
@ -19,7 +19,8 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
pub(crate) fn u16_from_input(
&mut self,
cs: &mut CS,
parameter_model: InputModel<F, G>,
name: String,
private: bool,
integer_option: Option<usize>,
) -> Result<ConstrainedValue<F, G>, IntegerError> {
// Type cast to u16 in rust.
@ -27,8 +28,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
let u16_option = integer_option.map(|integer| integer as u16);
// Check visibility of parameter
let name = parameter_model.variable.name.clone();
let integer_value = if parameter_model.private {
let integer_value = if private {
UInt16::alloc(cs.ns(|| name), || {
u16_option.ok_or(SynthesisError::AssignmentMissing)
})?

View File

@ -3,7 +3,7 @@
use crate::{
constraints::{ConstrainedProgram, ConstrainedValue},
errors::IntegerError,
types::{InputModel, Integer},
types::Integer,
};
use snarkos_errors::gadgets::SynthesisError;
@ -19,7 +19,8 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
pub(crate) fn u32_from_input(
&mut self,
cs: &mut CS,
parameter_model: InputModel<F, G>,
name: String,
private: bool,
integer_option: Option<usize>,
) -> Result<ConstrainedValue<F, G>, IntegerError> {
// Type cast to u32 in rust.
@ -27,8 +28,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
let u32_option = integer_option.map(|integer| integer as u32);
// Check visibility of parameter
let name = parameter_model.variable.name.clone();
let integer_value = if parameter_model.private {
let integer_value = if private {
UInt32::alloc(cs.ns(|| name), || {
u32_option.ok_or(SynthesisError::AssignmentMissing)
})?

View File

@ -3,7 +3,7 @@
use crate::{
constraints::{ConstrainedProgram, ConstrainedValue},
errors::IntegerError,
types::{InputModel, Integer},
types::Integer,
};
use snarkos_errors::gadgets::SynthesisError;
@ -19,7 +19,8 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
pub(crate) fn u64_from_input(
&mut self,
cs: &mut CS,
parameter_model: InputModel<F, G>,
name: String,
private: bool,
integer_option: Option<usize>,
) -> Result<ConstrainedValue<F, G>, IntegerError> {
// Type cast to u64 in rust.
@ -27,8 +28,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
let u64_option = integer_option.map(|integer| integer as u64);
// Check visibility of parameter
let name = parameter_model.variable.name.clone();
let integer_value = if parameter_model.private {
let integer_value = if private {
UInt64::alloc(cs.ns(|| name), || {
u64_option.ok_or(SynthesisError::AssignmentMissing)
})?

View File

@ -3,7 +3,7 @@
use crate::{
constraints::{ConstrainedProgram, ConstrainedValue},
errors::IntegerError,
types::{InputModel, Integer},
types::Integer,
};
use snarkos_errors::gadgets::SynthesisError;
@ -19,7 +19,8 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
pub(crate) fn u8_from_input(
&mut self,
cs: &mut CS,
parameter_model: InputModel<F, G>,
name: String,
private: bool,
integer_option: Option<usize>,
) -> Result<ConstrainedValue<F, G>, IntegerError> {
// Type cast to u8 in rust.
@ -27,8 +28,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
let u8_option = integer_option.map(|integer| integer as u8);
// Check visibility of parameter
let name = parameter_model.variable.name.clone();
let integer_value = if parameter_model.private {
let integer_value = if private {
UInt8::alloc(cs.ns(|| name), || {
u8_option.ok_or(SynthesisError::AssignmentMissing)
})?

View File

@ -1,6 +1,6 @@
//! An in memory store to keep track of defined names when constraining a Leo program.
use crate::{constraints::ConstrainedValue, types::Variable};
use crate::{constraints::ConstrainedValue, types::Identifier};
use snarkos_models::{
curves::{Field, Group, PrimeField},
@ -9,7 +9,7 @@ use snarkos_models::{
use std::{collections::HashMap, marker::PhantomData};
pub struct ConstrainedProgram<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> {
pub resolved_names: HashMap<String, ConstrainedValue<F, G>>,
pub identifiers: HashMap<String, ConstrainedValue<F, G>>,
pub _cs: PhantomData<CS>,
}
@ -19,16 +19,16 @@ pub fn new_scope(outer: String, inner: String) -> String {
pub fn new_scope_from_variable<F: Field + PrimeField, G: Group>(
outer: String,
inner: &Variable<F, G>,
inner: &Identifier<F, G>,
) -> String {
new_scope(outer, inner.name.clone())
}
pub fn new_variable_from_variable<F: Field + PrimeField, G: Group>(
outer: String,
inner: &Variable<F, G>,
) -> Variable<F, G> {
Variable {
inner: &Identifier<F, G>,
) -> Identifier<F, G> {
Identifier {
name: new_scope_from_variable(outer, inner),
_engine: PhantomData::<F>,
_group: PhantomData::<G>,
@ -36,10 +36,10 @@ pub fn new_variable_from_variable<F: Field + PrimeField, G: Group>(
}
pub fn new_variable_from_variables<F: Field + PrimeField, G: Group>(
outer: &Variable<F, G>,
inner: &Variable<F, G>,
) -> Variable<F, G> {
Variable {
outer: &Identifier<F, G>,
inner: &Identifier<F, G>,
) -> Identifier<F, G> {
Identifier {
name: new_scope_from_variable(outer.name.clone(), inner),
_engine: PhantomData::<F>,
_group: PhantomData::<G>,
@ -49,42 +49,42 @@ pub fn new_variable_from_variables<F: Field + PrimeField, G: Group>(
impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgram<F, G, CS> {
pub fn new() -> Self {
Self {
resolved_names: HashMap::new(),
identifiers: HashMap::new(),
_cs: PhantomData::<CS>,
}
}
pub(crate) fn store(&mut self, name: String, value: ConstrainedValue<F, G>) {
self.resolved_names.insert(name, value);
self.identifiers.insert(name, value);
}
pub(crate) fn store_variable(
&mut self,
variable: Variable<F, G>,
variable: Identifier<F, G>,
value: ConstrainedValue<F, G>,
) {
self.store(variable.name, value);
}
pub(crate) fn contains_name(&self, name: &String) -> bool {
self.resolved_names.contains_key(name)
self.identifiers.contains_key(name)
}
pub(crate) fn contains_variable(&self, variable: &Variable<F, G>) -> bool {
pub(crate) fn contains_variable(&self, variable: &Identifier<F, G>) -> bool {
self.contains_name(&variable.name)
}
pub(crate) fn get(&self, name: &String) -> Option<&ConstrainedValue<F, G>> {
self.resolved_names.get(name)
self.identifiers.get(name)
}
pub(crate) fn get_mut(&mut self, name: &String) -> Option<&mut ConstrainedValue<F, G>> {
self.resolved_names.get_mut(name)
self.identifiers.get_mut(name)
}
pub(crate) fn get_mut_variable(
&mut self,
variable: &Variable<F, G>,
variable: &Identifier<F, G>,
) -> Option<&mut ConstrainedValue<F, G>> {
self.get_mut(&variable.name)
}

View File

@ -3,10 +3,12 @@
use crate::{
constraints::{new_scope_from_variable, ConstrainedProgram, ConstrainedValue},
errors::StatementError,
new_scope,
types::{
Assignee, ConditionalNestedOrEnd, ConditionalStatement, Expression, Integer,
RangeOrExpression, Statement, Type, Variable,
Assignee, ConditionalNestedOrEnd, ConditionalStatement, Expression, Identifier, Integer,
RangeOrExpression, Statement, Type,
},
Variable,
};
use snarkos_models::{
@ -17,7 +19,7 @@ use snarkos_models::{
impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgram<F, G, CS> {
fn resolve_assignee(&mut self, scope: String, assignee: Assignee<F, G>) -> String {
match assignee {
Assignee::Variable(name) => new_scope_from_variable(scope, &name),
Assignee::Identifier(name) => new_scope_from_variable(scope, &name),
Assignee::Array(array, _index) => self.resolve_assignee(scope, *array),
Assignee::CircuitMember(circuit_variable, _member) => {
self.resolve_assignee(scope, *circuit_variable)
@ -34,7 +36,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
return_value: &mut ConstrainedValue<F, G>,
) -> Result<(), StatementError> {
match assignee {
Assignee::Variable(name) => {
Assignee::Identifier(name) => {
// Store the variable in the current scope
let definition_name = new_scope_from_variable(function_scope.clone(), &name);
@ -147,31 +149,41 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
}
}
fn store_definition(
&mut self,
function_scope: String,
variable: Variable<F, G>,
mut value: ConstrainedValue<F, G>,
) -> Result<(), StatementError> {
// Check optional explicit type
if let Some(_type) = variable._type {
value.expect_type(&_type)?;
}
// Store with given mutability
if variable.mutable {
value = ConstrainedValue::Mutable(Box::new(value));
}
let variable_program_identifier = new_scope(function_scope, variable.identifier.name);
self.store(variable_program_identifier, value);
Ok(())
}
fn enforce_definition_statement(
&mut self,
cs: &mut CS,
file_scope: String,
function_scope: String,
assignee: Assignee<F, G>,
ty: Option<Type<F, G>>,
variable: Variable<F, G>,
expression: Expression<F, G>,
) -> Result<(), StatementError> {
let result_value = &mut self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expression,
)?;
let value =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), expression)?;
match ty {
// Explicit type
Some(ty) => {
result_value.expect_type(&ty)?;
self.store_assignment(cs, file_scope, function_scope, assignee, result_value)
}
// Implicit type
None => self.store_assignment(cs, file_scope, function_scope, assignee, result_value),
}
self.store_definition(function_scope, variable, value)
}
fn enforce_multiple_definition_statement(
@ -179,7 +191,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
cs: &mut CS,
file_scope: String,
function_scope: String,
assignees: Vec<Assignee<F, G>>,
variables: Vec<Variable<F, G>>,
function: Expression<F, G>,
) -> Result<(), StatementError> {
// Expect return values from function
@ -196,20 +208,16 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
),
};
assignees
.into_iter()
.zip(return_values.into_iter())
.map(|(assignee, mut return_value)| {
self.store_assignment(
cs,
file_scope.clone(),
function_scope.clone(),
assignee,
&mut return_value,
)
})
.collect::<Result<Vec<_>, _>>()?;
if variables.len() != return_values.len() {
return Err(StatementError::InvalidNumberOfDefinitions(
variables.len(),
return_values.len(),
));
}
for (variable, value) in variables.into_iter().zip(return_values.into_iter()) {
self.store_definition(function_scope.clone(), variable, value)?;
}
Ok(())
}
@ -326,7 +334,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
cs: &mut CS,
file_scope: String,
function_scope: String,
index: Variable<F, G>,
index: Identifier<F, G>,
start: Integer,
stop: Integer,
statements: Vec<Statement<F, G>>,
@ -413,13 +421,12 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
return_types,
)?);
}
Statement::Definition(assignee, ty, expression) => {
Statement::Definition(variable, expression) => {
self.enforce_definition_statement(
cs,
file_scope,
function_scope,
assignee,
ty,
variable,
expression,
)?;
}
@ -432,12 +439,12 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
expression,
)?;
}
Statement::MultipleAssign(assignees, function) => {
Statement::MultipleAssign(variables, function) => {
self.enforce_multiple_definition_statement(
cs,
file_scope,
function_scope,
assignees,
variables,
function,
)?;
}

View File

@ -2,7 +2,7 @@
use crate::{
errors::ValueError,
types::{Circuit, FieldElement, Function, Type, Variable},
types::{Circuit, FieldElement, Function, Identifier, Type},
Integer,
};
@ -14,7 +14,7 @@ use std::fmt;
#[derive(Clone, PartialEq, Eq)]
pub struct ConstrainedCircuitMember<F: Field + PrimeField, G: Group>(
pub Variable<F, G>,
pub Identifier<F, G>,
pub ConstrainedValue<F, G>,
);
@ -26,9 +26,10 @@ pub enum ConstrainedValue<F: Field + PrimeField, G: Group> {
Boolean(Boolean),
Array(Vec<ConstrainedValue<F, G>>),
CircuitDefinition(Circuit<F, G>),
CircuitExpression(Variable<F, G>, Vec<ConstrainedCircuitMember<F, G>>),
CircuitExpression(Identifier<F, G>, Vec<ConstrainedCircuitMember<F, G>>),
Function(Function<F, G>),
Return(Vec<ConstrainedValue<F, G>>), // add Null for function returns
Return(Vec<ConstrainedValue<F, G>>),
Mutable(Box<ConstrainedValue<F, G>>),
}
impl<F: Field + PrimeField, G: Group> ConstrainedValue<F, G> {
@ -73,6 +74,9 @@ impl<F: Field + PrimeField, G: Group> ConstrainedValue<F, G> {
value.expect_type(_type)?;
}
}
(ConstrainedValue::Mutable(ref value), _type) => {
value.expect_type(&_type)?;
}
(value, _type) => {
return Err(ValueError::TypeError(format!(
"expected type {}, got {}",
@ -126,6 +130,7 @@ impl<F: Field + PrimeField, G: Group> fmt::Display for ConstrainedValue<F, G> {
unimplemented!("cannot return struct definition in program")
}
ConstrainedValue::Function(ref function) => write!(f, "{}();", function.function_name),
ConstrainedValue::Mutable(ref value) => write!(f, "mut {}", value),
}
}
}

View File

@ -5,8 +5,8 @@ pub enum IntegerError {
#[error("expected integer parameter type, got {}", _0)]
InvalidType(String),
#[error("Expected integer {} parameter, got {}", _0, _1)]
InvalidInteger(String, String),
#[error("Expected integer parameter, got {}", _0)]
InvalidInteger(String),
#[error("Cannot evaluate {}", _0)]
CannotEvaluate(String),

View File

@ -20,6 +20,7 @@ pub enum StatementError {
#[error("{}", _0)]
ValueError(ValueError),
// Arrays
#[error("Cannot assign single index to array of values")]
ArrayAssignIndex,
@ -29,12 +30,21 @@ pub enum StatementError {
#[error("Cannot assign to unknown array {}", _0)]
UndefinedArray(String),
// Circuits
#[error("Attempted to assign to unknown circuit {}", _0)]
UndefinedCircuit(String),
#[error("Attempted to assign to unknown circuit {}", _0)]
UndefinedCircuitObject(String),
// Statements
#[error(
"Multiple definition statement expected {} return values, got {}",
_0,
_1
)]
InvalidNumberOfDefinitions(usize, usize),
#[error("Function return statement expected {} return values, got {}", _0, _1)]
InvalidNumberOfReturns(usize, usize),

View File

@ -1,14 +1,14 @@
//! The Import type for a Leo program.
use crate::Variable;
use crate::Identifier;
use snarkos_models::curves::{Field, Group, PrimeField};
use std::fmt;
#[derive(Clone)]
pub struct ImportSymbol<F: Field + PrimeField, G: Group> {
pub symbol: Variable<F, G>,
pub alias: Option<Variable<F, G>>,
pub symbol: Identifier<F, G>,
pub alias: Option<Identifier<F, G>>,
}
#[derive(Clone)]

View File

@ -98,10 +98,8 @@ expression_primitive = { value | identifier }
/// Variables + Mutability
mutable = {"mut"}
variable = {mutable? ~ identifier}
optionally_typed_variable = { (_type ~ variable) | (variable)}
optionally_typed_variable_tuple = _{ optionally_typed_variable ~ ("," ~ optionally_typed_variable)* }
variable = { mutable? ~ identifier ~ (":" ~ _type)? }
variable_tuple = _{ variable ~ ("," ~ variable)* }
/// Access
@ -172,9 +170,9 @@ conditional_nested_or_end = { statement_conditional | "{" ~ NEWLINE* ~ statement
/// Statements
statement_return = { "return" ~ expression_tuple }
statement_definition = { "let" ~ variable ~ (":" ~ _type)? ~ "=" ~ expression }
statement_definition = { "let" ~ variable ~ "=" ~ expression }
statement_assign = { assignee ~ operation_assign ~ expression }
statement_multiple_assignment = { "let" ~ "(" ~ optionally_typed_variable_tuple ~ ")" ~ "=" ~ identifier ~ "(" ~ expression_tuple ~ ")" }
statement_multiple_assignment = { "let" ~ "(" ~ variable_tuple ~ ")" ~ "=" ~ identifier ~ "(" ~ expression_tuple ~ ")" }
statement_conditional = {"if" ~ (expression | "(" ~ expression ~ ")") ~ "{" ~ NEWLINE* ~ statement+ ~ "}" ~ ("else" ~ conditional_nested_or_end)?}
statement_for = { "for" ~ identifier ~ "in" ~ expression ~ ".." ~ expression ~ "{" ~ NEWLINE* ~ statement+ ~ "}"}
statement_assert = {
@ -198,10 +196,10 @@ statement = {
/// Functions
parameter = {variable ~ ":" ~ visibility? ~ _type}
parameter_list = _{(parameter ~ ("," ~ parameter)*)?}
input_model = {mutable? ~ identifier ~ ":" ~ visibility? ~ _type}
input_model_list = _{(input_model ~ ("," ~ input_model)*)?}
function_definition = {"function" ~ identifier ~ "(" ~ parameter_list ~ ")" ~ ("->" ~ (_type | "(" ~ type_list ~ ")"))? ~ "{" ~ NEWLINE* ~ statement* ~ NEWLINE* ~ "}" ~ NEWLINE* }
function_definition = {"function" ~ identifier ~ "(" ~ input_model_list ~ ")" ~ ("->" ~ (_type | "(" ~ type_list ~ ")"))? ~ "{" ~ NEWLINE* ~ statement* ~ NEWLINE* ~ "}" ~ NEWLINE* }
/// Utilities

View File

@ -3,7 +3,6 @@
use crate::{errors::IntegerError, Import};
use crate::errors::ValueError;
use snarkos_models::curves::{Field, Group, PrimeField};
use snarkos_models::gadgets::{
r1cs::Variable as R1CSVariable,
@ -17,13 +16,13 @@ use std::marker::PhantomData;
/// A variable in a constraint system.
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Variable<F: Field + PrimeField, G: Group> {
pub struct Identifier<F: Field + PrimeField, G: Group> {
pub name: String,
pub(crate) _group: PhantomData<G>,
pub(crate) _engine: PhantomData<F>,
}
impl<F: Field + PrimeField, G: Group> Variable<F, G> {
impl<F: Field + PrimeField, G: Group> Identifier<F, G> {
pub fn new(name: String) -> Self {
Self {
name,
@ -33,6 +32,13 @@ impl<F: Field + PrimeField, G: Group> Variable<F, G> {
}
}
#[derive(Clone, PartialEq, Eq)]
pub struct Variable<F: Field + PrimeField, G: Group> {
pub identifier: Identifier<F, G>,
pub mutable: bool,
pub _type: Option<Type<F, G>>,
}
/// An integer type enum wrapping the integer value. Used only in expressions.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Integer {
@ -108,8 +114,8 @@ pub enum SpreadOrExpression<F: Field + PrimeField, G: Group> {
/// Expression that evaluates to a value
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Expression<F: Field + PrimeField, G: Group> {
// Variable
Variable(Variable<F, G>),
// Identifier
Identifier(Identifier<F, G>),
// Values
Integer(Integer),
@ -146,19 +152,19 @@ pub enum Expression<F: Field + PrimeField, G: Group> {
ArrayAccess(Box<Expression<F, G>>, Box<RangeOrExpression<F, G>>), // (array name, range)
// Circuits
Circuit(Variable<F, G>, Vec<CircuitMember<F, G>>),
CircuitMemberAccess(Box<Expression<F, G>>, Variable<F, G>), // (circuit name, circuit member name)
Circuit(Identifier<F, G>, Vec<CircuitMember<F, G>>),
CircuitMemberAccess(Box<Expression<F, G>>, Identifier<F, G>), // (circuit name, circuit member name)
// Functions
FunctionCall(Variable<F, G>, Vec<Expression<F, G>>),
FunctionCall(Identifier<F, G>, Vec<Expression<F, G>>),
}
/// Definition assignee: v, arr[0..2], Point p.x
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Assignee<F: Field + PrimeField, G: Group> {
Variable(Variable<F, G>),
Identifier(Identifier<F, G>),
Array(Box<Assignee<F, G>>, RangeOrExpression<F, G>),
CircuitMember(Box<Assignee<F, G>>, Variable<F, G>),
CircuitMember(Box<Assignee<F, G>>, Identifier<F, G>),
}
/// Explicit integer type
@ -179,7 +185,7 @@ pub enum Type<F: Field + PrimeField, G: Group> {
GroupElement,
Boolean,
Array(Box<Type<F, G>>, Vec<usize>),
Circuit(Variable<F, G>),
Circuit(Identifier<F, G>),
}
impl<F: Field + PrimeField, G: Group> Type<F, G> {
@ -213,32 +219,31 @@ pub struct ConditionalStatement<F: Field + PrimeField, G: Group> {
/// Program statement that defines some action (or expression) to be carried out.
#[derive(Clone, PartialEq, Eq)]
pub enum Statement<F: Field + PrimeField, G: Group> {
// Declaration(Variable),
Return(Vec<Expression<F, G>>),
Definition(Assignee<F, G>, Option<Type<F, G>>, Expression<F, G>),
Definition(Variable<F, G>, Expression<F, G>),
Assign(Assignee<F, G>, Expression<F, G>),
MultipleAssign(Vec<Assignee<F, G>>, Expression<F, G>),
MultipleAssign(Vec<Variable<F, G>>, Expression<F, G>),
Conditional(ConditionalStatement<F, G>),
For(Variable<F, G>, Integer, Integer, Vec<Statement<F, G>>),
For(Identifier<F, G>, Integer, Integer, Vec<Statement<F, G>>),
AssertEq(Expression<F, G>, Expression<F, G>),
Expression(Expression<F, G>),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CircuitMember<F: Field + PrimeField, G: Group> {
pub variable: Variable<F, G>,
pub identifier: Identifier<F, G>,
pub expression: Expression<F, G>,
}
#[derive(Clone, PartialEq, Eq)]
pub struct CircuitObject<F: Field + PrimeField, G: Group> {
pub variable: Variable<F, G>,
pub identifier: Identifier<F, G>,
pub _type: Type<F, G>,
}
#[derive(Clone, PartialEq, Eq)]
pub struct Circuit<F: Field + PrimeField, G: Group> {
pub variable: Variable<F, G>,
pub identifier: Identifier<F, G>,
pub fields: Vec<CircuitObject<F, G>>,
}
@ -246,18 +251,10 @@ pub struct Circuit<F: Field + PrimeField, G: Group> {
#[derive(Clone, PartialEq, Eq)]
pub struct InputModel<F: Field + PrimeField, G: Group> {
pub identifier: Identifier<F, G>,
pub mutable: bool,
pub private: bool,
pub _type: Type<F, G>,
pub variable: Variable<F, G>,
}
impl<F: Field + PrimeField, G: Group> InputModel<F, G> {
pub fn inner_type(&self) -> Result<Type<F, G>, ValueError> {
match &self._type {
Type::Array(ref _type, _length) => Ok(*_type.clone()),
ref _type => Err(ValueError::ArrayModel(_type.to_string())),
}
}
}
#[derive(Clone, PartialEq, Eq)]
@ -271,7 +268,7 @@ pub enum InputValue<F: Field + PrimeField, G: Group> {
#[derive(Clone, PartialEq, Eq)]
pub struct Function<F: Field + PrimeField, G: Group> {
pub function_name: Variable<F, G>,
pub function_name: Identifier<F, G>,
pub inputs: Vec<InputModel<F, G>>,
pub returns: Vec<Type<F, G>>,
pub statements: Vec<Statement<F, G>>,
@ -286,21 +283,17 @@ impl<F: Field + PrimeField, G: Group> Function<F, G> {
/// A simple program with statement expressions, program arguments and program returns.
#[derive(Debug, Clone)]
pub struct Program<F: Field + PrimeField, G: Group> {
pub name: Variable<F, G>,
pub name: Identifier<F, G>,
pub num_parameters: usize,
pub imports: Vec<Import<F, G>>,
pub circuits: HashMap<Variable<F, G>, Circuit<F, G>>,
pub functions: HashMap<Variable<F, G>, Function<F, G>>,
pub circuits: HashMap<Identifier<F, G>, Circuit<F, G>>,
pub functions: HashMap<Identifier<F, G>, Function<F, G>>,
}
impl<'ast, F: Field + PrimeField, G: Group> Program<F, G> {
pub fn new() -> Self {
Self {
name: Variable {
name: "".into(),
_group: PhantomData::<G>,
_engine: PhantomData::<F>,
},
name: Identifier::new("".into()),
num_parameters: 0,
imports: vec![],
circuits: HashMap::new(),
@ -313,11 +306,7 @@ impl<'ast, F: Field + PrimeField, G: Group> Program<F, G> {
}
pub fn name(mut self, name: String) -> Self {
self.name = Variable {
name,
_group: PhantomData::<G>,
_engine: PhantomData::<F>,
};
self.name = Identifier::new(name);
self
}
}

View File

@ -2,24 +2,40 @@
use crate::{
Assignee, Circuit, CircuitObject, ConditionalNestedOrEnd, ConditionalStatement, Expression,
FieldElement, Function, InputModel, InputValue, Integer, IntegerType,
FieldElement, Function, Identifier, InputModel, InputValue, Integer, IntegerType,
RangeOrExpression, SpreadOrExpression, Statement, Type, Variable,
};
use snarkos_models::curves::{Field, Group, PrimeField};
use std::fmt;
impl<F: Field + PrimeField, G: Group> fmt::Display for Variable<F, G> {
impl<F: Field + PrimeField, G: Group> fmt::Display for Identifier<F, G> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.name)
}
}
impl<F: Field + PrimeField, G: Group> fmt::Debug for Variable<F, G> {
impl<F: Field + PrimeField, G: Group> fmt::Debug for Identifier<F, G> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.name)
}
}
impl<F: Field + PrimeField, G: Group> fmt::Display for Variable<F, G> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.mutable {
write!(f, "mut ")?;
}
write!(f, "{}", self.identifier)?;
if self._type.is_some() {
write!(f, ": {}", self._type.as_ref().unwrap())?;
}
write!(f, "")
}
}
impl fmt::Display for Integer {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}{}", self.to_usize(), self.get_type())
@ -84,7 +100,7 @@ impl<'ast, F: Field + PrimeField, G: Group> fmt::Display for Expression<F, G> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
// Variables
Expression::Variable(ref variable) => write!(f, "{}", variable),
Expression::Identifier(ref variable) => write!(f, "{}", variable),
// Values
Expression::Integer(ref integer) => write!(f, "{}", integer),
@ -131,7 +147,7 @@ impl<'ast, F: Field + PrimeField, G: Group> fmt::Display for Expression<F, G> {
Expression::Circuit(ref var, ref members) => {
write!(f, "{} {{", var)?;
for (i, member) in members.iter().enumerate() {
write!(f, "{}: {}", member.variable, member.expression)?;
write!(f, "{}: {}", member.identifier, member.expression)?;
if i < members.len() - 1 {
write!(f, ", ")?;
}
@ -160,7 +176,7 @@ impl<'ast, F: Field + PrimeField, G: Group> fmt::Display for Expression<F, G> {
impl<F: Field + PrimeField, G: Group> fmt::Display for Assignee<F, G> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Assignee::Variable(ref variable) => write!(f, "{}", variable),
Assignee::Identifier(ref variable) => write!(f, "{}", variable),
Assignee::Array(ref array, ref index) => write!(f, "{}[{}]", array, index),
Assignee::CircuitMember(ref circuit_variable, ref member) => {
write!(f, "{}.{}", circuit_variable, member)
@ -210,10 +226,9 @@ impl<F: Field + PrimeField, G: Group> fmt::Display for Statement<F, G> {
}
write!(f, ")\n")
}
Statement::Definition(ref assignee, ref ty, ref expression) => match ty {
Some(ref ty) => write!(f, "let {}: {} = {};", assignee, ty, expression),
None => write!(f, "let {} = {};", assignee, expression),
},
Statement::Definition(ref variable, ref expression) => {
write!(f, "let {} = {};", variable, expression)
}
Statement::Assign(ref variable, ref statement) => {
write!(f, "{} = {};", variable, statement)
}
@ -276,13 +291,13 @@ impl<F: Field + PrimeField, G: Group> fmt::Display for Type<F, G> {
impl<F: Field + PrimeField, G: Group> fmt::Display for CircuitObject<F, G> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}: {}", self.variable, self._type)
write!(f, "{}: {}", self.identifier, self._type)
}
}
impl<F: Field + PrimeField, G: Group> Circuit<F, G> {
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "circuit {} {{ \n", self.variable)?;
write!(f, "circuit {} {{ \n", self.identifier)?;
for field in self.fields.iter() {
write!(f, " {}\n", field)?;
}
@ -304,8 +319,17 @@ impl<F: Field + PrimeField, G: Group> fmt::Debug for Circuit<F, G> {
impl<F: Field + PrimeField, G: Group> fmt::Display for InputModel<F, G> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let visibility = if self.private { "private" } else { "public" };
write!(f, "{}: {} {}", self.variable, visibility, self._type,)
// mut var: private bool
if self.mutable {
write!(f, "mut ")?;
}
write!(f, "{}: ", self.identifier)?;
if self.private {
write!(f, "private ")?;
} else {
write!(f, "public ")?;
}
write!(f, "{}", self._type)
}
}

View File

@ -7,27 +7,38 @@ use snarkos_models::gadgets::utilities::{
boolean::Boolean, uint128::UInt128, uint16::UInt16, uint32::UInt32, uint64::UInt64,
uint8::UInt8,
};
use std::{collections::HashMap};
use std::collections::HashMap;
/// pest ast -> types::Identifier
impl<'ast, F: Field + PrimeField, G: Group> From<ast::Identifier<'ast>>
for types::Identifier<F, G>
{
fn from(identifier: ast::Identifier<'ast>) -> Self {
types::Identifier::new(identifier.value)
}
}
impl<'ast, F: Field + PrimeField, G: Group> From<ast::Identifier<'ast>>
for types::Expression<F, G>
{
fn from(identifier: ast::Identifier<'ast>) -> Self {
types::Expression::Identifier(types::Identifier::from(identifier))
}
}
/// pest ast -> types::Variable
impl<'ast, F: Field + PrimeField, G: Group> From<ast::Variable<'ast>> for types::Variable<F, G> {
fn from(variable: ast::Variable<'ast>) -> Self {
types::Variable::new(variable.identifier.value)
types::Variable {
identifier: types::Identifier::from(variable.identifier),
mutable: variable.mutable.is_some(),
_type: variable._type.map(|_type| types::Type::from(_type)),
}
}
}
impl<'ast, F: Field + PrimeField, G: Group> From<ast::Identifier<'ast>> for types::Variable<F, G> {
fn from(identifier: ast::Identifier<'ast>) -> Self {
types::Variable::new(identifier.value)
}
}
impl<'ast, F: Field + PrimeField, G: Group> From<ast::Identifier<'ast>> for types::Expression<F, G> {
fn from(identifier: ast::Identifier<'ast>) -> Self {
types::Expression::Variable(types::Variable::from(identifier))
}
}
/// pest ast - types::Integer
impl<'ast> types::Integer {
@ -270,7 +281,7 @@ impl<'ast, F: Field + PrimeField, G: Group> From<ast::InlineCircuitMember<'ast>>
{
fn from(member: ast::InlineCircuitMember<'ast>) -> Self {
types::CircuitMember {
variable: types::Variable::from(member.identifier),
identifier: types::Identifier::from(member.identifier),
expression: types::Expression::from(member.expression),
}
}
@ -280,7 +291,7 @@ impl<'ast, F: Field + PrimeField, G: Group> From<ast::CircuitInlineExpression<'a
for types::Expression<F, G>
{
fn from(expression: ast::CircuitInlineExpression<'ast>) -> Self {
let variable = types::Variable::from(expression.identifier);
let variable = types::Identifier::from(expression.identifier);
let members = expression
.members
.into_iter()
@ -295,7 +306,8 @@ impl<'ast, F: Field + PrimeField, G: Group> From<ast::PostfixExpression<'ast>>
for types::Expression<F, G>
{
fn from(expression: ast::PostfixExpression<'ast>) -> Self {
let variable = types::Expression::Variable(types::Variable::from(expression.identifier));
let variable =
types::Expression::Identifier(types::Identifier::from(expression.identifier));
// ast::PostFixExpression contains an array of "accesses": `a(34)[42]` is represented as `[a, [Call(34), Select(42)]]`, but Access call expressions
// are recursive, so it is `Select(Call(a, 34), 42)`. We apply this transformation here
@ -306,7 +318,7 @@ impl<'ast, F: Field + PrimeField, G: Group> From<ast::PostfixExpression<'ast>>
.into_iter()
.fold(variable, |acc, access| match access {
ast::Access::Call(function) => match acc {
types::Expression::Variable(variable) => types::Expression::FunctionCall(
types::Expression::Identifier(variable) => types::Expression::FunctionCall(
variable,
function
.expressions
@ -320,7 +332,7 @@ impl<'ast, F: Field + PrimeField, G: Group> From<ast::PostfixExpression<'ast>>
},
ast::Access::Member(struct_member) => types::Expression::CircuitMemberAccess(
Box::new(acc),
types::Variable::from(struct_member.identifier),
types::Identifier::from(struct_member.identifier),
),
ast::Access::Array(array) => types::Expression::ArrayAccess(
Box::new(acc),
@ -364,7 +376,7 @@ impl<'ast, F: Field + PrimeField, G: Group> types::Expression<F, G> {
// ast::Assignee -> types::Expression for operator assign statements
impl<'ast, F: Field + PrimeField, G: Group> From<ast::Assignee<'ast>> for types::Expression<F, G> {
fn from(assignee: ast::Assignee<'ast>) -> Self {
let variable = types::Expression::Variable(types::Variable::from(assignee.identifier));
let variable = types::Expression::Identifier(types::Identifier::from(assignee.identifier));
// we start with the id, and we fold the array of accesses by wrapping the current value
assignee
@ -374,7 +386,7 @@ impl<'ast, F: Field + PrimeField, G: Group> From<ast::Assignee<'ast>> for types:
ast::AssigneeAccess::Member(struct_member) => {
types::Expression::CircuitMemberAccess(
Box::new(acc),
types::Variable::from(struct_member.identifier),
types::Identifier::from(struct_member.identifier),
)
}
ast::AssigneeAccess::Array(array) => types::Expression::ArrayAccess(
@ -389,7 +401,7 @@ impl<'ast, F: Field + PrimeField, G: Group> From<ast::Assignee<'ast>> for types:
impl<'ast, F: Field + PrimeField, G: Group> From<ast::Identifier<'ast>> for types::Assignee<F, G> {
fn from(variable: ast::Identifier<'ast>) -> Self {
types::Assignee::Variable(types::Variable::from(variable))
types::Assignee::Identifier(types::Identifier::from(variable))
}
}
@ -408,7 +420,7 @@ impl<'ast, F: Field + PrimeField, G: Group> From<ast::Assignee<'ast>> for types:
),
ast::AssigneeAccess::Member(struct_member) => types::Assignee::CircuitMember(
Box::new(acc),
types::Variable::from(struct_member.identifier),
types::Identifier::from(struct_member.identifier),
),
})
}
@ -435,10 +447,7 @@ impl<'ast, F: Field + PrimeField, G: Group> From<ast::DefinitionStatement<'ast>>
{
fn from(statement: ast::DefinitionStatement<'ast>) -> Self {
types::Statement::Definition(
types::Assignee::from(statement.variable.identifier),
statement
._type
.map(|_type| types::Type::<F, G>::from(_type)),
types::Variable::from(statement.variable),
types::Expression::from(statement.expression),
)
}
@ -506,16 +515,16 @@ impl<'ast, F: Field + PrimeField, G: Group> From<ast::MultipleAssignmentStatemen
for types::Statement<F, G>
{
fn from(statement: ast::MultipleAssignmentStatement<'ast>) -> Self {
let assignees = statement
.assignees
let variables = statement
.variables
.into_iter()
.map(|i| types::Assignee::Variable(types::Variable::from(i.variable.identifier)))
.map(|typed_variable| types::Variable::from(typed_variable))
.collect();
types::Statement::MultipleAssign(
assignees,
variables,
types::Expression::FunctionCall(
types::Variable::from(statement.function_name),
types::Identifier::from(statement.function_name),
statement
.arguments
.into_iter()
@ -577,7 +586,7 @@ impl<'ast, F: Field + PrimeField, G: Group> From<ast::ForStatement<'ast>>
};
types::Statement::For(
types::Variable::from(statement.index),
types::Identifier::from(statement.index),
from,
to,
statement
@ -669,7 +678,7 @@ impl<'ast, F: Field + PrimeField, G: Group> From<ast::ArrayType<'ast>> for types
impl<'ast, F: Field + PrimeField, G: Group> From<ast::CircuitType<'ast>> for types::Type<F, G> {
fn from(struct_type: ast::CircuitType<'ast>) -> Self {
types::Type::Circuit(types::Variable::from(struct_type.identifier))
types::Type::Circuit(types::Identifier::from(struct_type.identifier))
}
}
@ -690,7 +699,7 @@ impl<'ast, F: Field + PrimeField, G: Group> From<ast::CircuitObject<'ast>>
{
fn from(struct_field: ast::CircuitObject<'ast>) -> Self {
types::CircuitObject {
variable: types::Variable::from(struct_field.identifier),
identifier: types::Identifier::from(struct_field.identifier),
_type: types::Type::from(struct_field._type),
}
}
@ -698,40 +707,34 @@ impl<'ast, F: Field + PrimeField, G: Group> From<ast::CircuitObject<'ast>>
impl<'ast, F: Field + PrimeField, G: Group> From<ast::Circuit<'ast>> for types::Circuit<F, G> {
fn from(struct_definition: ast::Circuit<'ast>) -> Self {
let variable = types::Variable::from(struct_definition.identifier);
let variable = types::Identifier::from(struct_definition.identifier);
let fields = struct_definition
.fields
.into_iter()
.map(|struct_field| types::CircuitObject::from(struct_field))
.collect();
types::Circuit { variable, fields }
types::Circuit {
identifier: variable,
fields,
}
}
}
/// pest ast -> function types::Parameters
impl<'ast, F: Field + PrimeField, G: Group> From<ast::Parameter<'ast>> for types::InputModel<F, G> {
fn from(parameter: ast::Parameter<'ast>) -> Self {
let _type = types::Type::from(parameter._type);
let variable = types::Variable::from(parameter.variable);
if parameter.visibility.is_some() {
let private = match parameter.visibility.unwrap() {
ast::Visibility::Private(_) => true,
ast::Visibility::Public(_) => false,
};
types::InputModel {
private,
_type,
variable,
}
} else {
types::InputModel {
private: true,
_type,
variable,
}
impl<'ast, F: Field + PrimeField, G: Group> From<ast::InputModel<'ast>>
for types::InputModel<F, G>
{
fn from(parameter: ast::InputModel<'ast>) -> Self {
types::InputModel {
identifier: types::Identifier::from(parameter.identifier),
mutable: parameter.mutable.is_some(),
// private by default
private: parameter.visibility.map_or(true, |visibility| {
visibility.eq(&ast::Visibility::Private(ast::Private {}))
}),
_type: types::Type::from(parameter._type),
}
}
}
@ -740,7 +743,7 @@ impl<'ast, F: Field + PrimeField, G: Group> From<ast::Parameter<'ast>> for types
impl<'ast, F: Field + PrimeField, G: Group> From<ast::Function<'ast>> for types::Function<F, G> {
fn from(function_definition: ast::Function<'ast>) -> Self {
let function_name = types::Variable::from(function_definition.function_name);
let function_name = types::Identifier::from(function_definition.function_name);
let parameters = function_definition
.parameters
.into_iter()
@ -771,8 +774,8 @@ impl<'ast, F: Field + PrimeField, G: Group> From<ast::Function<'ast>> for types:
impl<'ast, F: Field + PrimeField, G: Group> From<ast::ImportSymbol<'ast>> for ImportSymbol<F, G> {
fn from(symbol: ast::ImportSymbol<'ast>) -> Self {
ImportSymbol {
symbol: types::Variable::from(symbol.value),
alias: symbol.alias.map(|alias| types::Variable::from(alias)),
symbol: types::Identifier::from(symbol.value),
alias: symbol.alias.map(|alias| types::Identifier::from(alias)),
}
}
}
@ -807,23 +810,23 @@ impl<'ast, F: Field + PrimeField, G: Group> types::Program<F, G> {
file.circuits.into_iter().for_each(|struct_def| {
structs.insert(
types::Variable::from(struct_def.identifier.clone()),
types::Identifier::from(struct_def.identifier.clone()),
types::Circuit::from(struct_def),
);
});
file.functions.into_iter().for_each(|function_def| {
functions.insert(
types::Variable::from(function_def.function_name.clone()),
types::Identifier::from(function_def.function_name.clone()),
types::Function::from(function_def),
);
});
if let Some(main_function) = functions.get(&types::Variable::new("main".into())) {
if let Some(main_function) = functions.get(&types::Identifier::new("main".into())) {
num_parameters = main_function.inputs.len();
}
types::Program {
name: types::Variable::new(name),
name: types::Identifier::new(name),
num_parameters,
imports,
circuits: structs,