mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-12-24 02:31:44 +03:00
Merge pull request #9 from AleoHQ/feature/mutability
Feature/mutability
This commit is contained in:
commit
4997d6e13c
@ -2,6 +2,18 @@ circuit Circ {
|
||||
x: u32
|
||||
}
|
||||
|
||||
function main() {
|
||||
let c = Circ { x: 4 };
|
||||
function main() -> u32 {
|
||||
let mut a = 1;
|
||||
a = 0;
|
||||
|
||||
let b = 1;
|
||||
//b = 0; // <- illegal
|
||||
|
||||
let mut arr = [1, 2];
|
||||
arr[0] = 0;
|
||||
|
||||
let mut c = Circ { x: 1 };
|
||||
c.x = 0;
|
||||
|
||||
return c.x
|
||||
}
|
@ -26,6 +26,23 @@ lazy_static! {
|
||||
static ref PRECEDENCE_CLIMBER: PrecClimber<Rule> = precedence_climber();
|
||||
}
|
||||
|
||||
// Identifiers
|
||||
|
||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||
#[pest_ast(rule(Rule::identifier))]
|
||||
pub struct Identifier<'ast> {
|
||||
#[pest_ast(outer(with(span_into_string)))]
|
||||
pub value: String,
|
||||
#[pest_ast(outer())]
|
||||
pub span: Span<'ast>,
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Display for Identifier<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.value)
|
||||
}
|
||||
}
|
||||
|
||||
// Visibility
|
||||
|
||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||
@ -176,7 +193,7 @@ pub struct BooleanType<'ast> {
|
||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||
#[pest_ast(rule(Rule::type_circuit))]
|
||||
pub struct CircuitType<'ast> {
|
||||
pub variable: Variable<'ast>,
|
||||
pub identifier: Identifier<'ast>,
|
||||
#[pest_ast(outer())]
|
||||
pub span: Span<'ast>,
|
||||
}
|
||||
@ -324,35 +341,35 @@ impl<'ast> fmt::Display for Value<'ast> {
|
||||
}
|
||||
}
|
||||
|
||||
// Variables
|
||||
// Variables + Mutability
|
||||
|
||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||
#[pest_ast(rule(Rule::mutable))]
|
||||
pub struct Mutable {}
|
||||
|
||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||
#[pest_ast(rule(Rule::variable))]
|
||||
pub struct Variable<'ast> {
|
||||
#[pest_ast(outer(with(span_into_string)))]
|
||||
pub value: String,
|
||||
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.value)
|
||||
}
|
||||
}
|
||||
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 id: 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.id)
|
||||
if let Some(ref _type) = self._type {
|
||||
write!(f, ": {}", _type)?;
|
||||
}
|
||||
|
||||
write!(f, "")
|
||||
}
|
||||
}
|
||||
|
||||
@ -423,7 +440,7 @@ pub struct ArrayAccess<'ast> {
|
||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||
#[pest_ast(rule(Rule::access_member))]
|
||||
pub struct MemberAccess<'ast> {
|
||||
pub variable: Variable<'ast>,
|
||||
pub identifier: Identifier<'ast>,
|
||||
#[pest_ast(outer())]
|
||||
pub span: Span<'ast>,
|
||||
}
|
||||
@ -439,7 +456,7 @@ pub enum Access<'ast> {
|
||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||
#[pest_ast(rule(Rule::expression_postfix))]
|
||||
pub struct PostfixExpression<'ast> {
|
||||
pub variable: Variable<'ast>,
|
||||
pub identifier: Identifier<'ast>,
|
||||
pub accesses: Vec<Access<'ast>>,
|
||||
#[pest_ast(outer())]
|
||||
pub span: Span<'ast>,
|
||||
@ -456,7 +473,7 @@ impl<'ast> fmt::Display for AssigneeAccess<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
AssigneeAccess::Array(ref array) => write!(f, "[{}]", array.expression),
|
||||
AssigneeAccess::Member(ref member) => write!(f, ".{}", member.variable),
|
||||
AssigneeAccess::Member(ref member) => write!(f, ".{}", member.identifier),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -464,7 +481,7 @@ impl<'ast> fmt::Display for AssigneeAccess<'ast> {
|
||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||
#[pest_ast(rule(Rule::assignee))]
|
||||
pub struct Assignee<'ast> {
|
||||
pub variable: Variable<'ast>,
|
||||
pub identifier: Identifier<'ast>,
|
||||
pub accesses: Vec<AssigneeAccess<'ast>>,
|
||||
#[pest_ast(outer())]
|
||||
pub span: Span<'ast>,
|
||||
@ -472,7 +489,7 @@ pub struct Assignee<'ast> {
|
||||
|
||||
impl<'ast> fmt::Display for Assignee<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.variable)?;
|
||||
write!(f, "{}", self.identifier)?;
|
||||
for (i, access) in self.accesses.iter().enumerate() {
|
||||
write!(f, "{}", access)?;
|
||||
if i < self.accesses.len() - 1 {
|
||||
@ -537,7 +554,7 @@ pub struct ArrayInitializerExpression<'ast> {
|
||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||
#[pest_ast(rule(Rule::circuit_object))]
|
||||
pub struct CircuitObject<'ast> {
|
||||
pub variable: Variable<'ast>,
|
||||
pub identifier: Identifier<'ast>,
|
||||
pub _type: Type<'ast>,
|
||||
#[pest_ast(outer())]
|
||||
pub span: Span<'ast>,
|
||||
@ -546,7 +563,7 @@ pub struct CircuitObject<'ast> {
|
||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||
#[pest_ast(rule(Rule::circuit_definition))]
|
||||
pub struct Circuit<'ast> {
|
||||
pub variable: Variable<'ast>,
|
||||
pub identifier: Identifier<'ast>,
|
||||
pub fields: Vec<CircuitObject<'ast>>,
|
||||
#[pest_ast(outer())]
|
||||
pub span: Span<'ast>,
|
||||
@ -555,7 +572,7 @@ pub struct Circuit<'ast> {
|
||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||
#[pest_ast(rule(Rule::inline_circuit_member))]
|
||||
pub struct InlineCircuitMember<'ast> {
|
||||
pub variable: Variable<'ast>,
|
||||
pub identifier: Identifier<'ast>,
|
||||
pub expression: Expression<'ast>,
|
||||
#[pest_ast(outer())]
|
||||
pub span: Span<'ast>,
|
||||
@ -564,7 +581,7 @@ pub struct InlineCircuitMember<'ast> {
|
||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||
#[pest_ast(rule(Rule::expression_inline_circuit))]
|
||||
pub struct CircuitInlineExpression<'ast> {
|
||||
pub variable: Variable<'ast>,
|
||||
pub identifier: Identifier<'ast>,
|
||||
pub members: Vec<InlineCircuitMember<'ast>>,
|
||||
#[pest_ast(outer())]
|
||||
pub span: Span<'ast>,
|
||||
@ -618,7 +635,7 @@ pub struct TernaryExpression<'ast> {
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Expression<'ast> {
|
||||
Value(Value<'ast>),
|
||||
Variable(Variable<'ast>),
|
||||
Identifier(Identifier<'ast>),
|
||||
Not(NotExpression<'ast>),
|
||||
// Increment(IncrementExpression<'ast>),
|
||||
// Decrement(DecrementExpression<'ast>),
|
||||
@ -662,7 +679,7 @@ impl<'ast> Expression<'ast> {
|
||||
pub fn span(&self) -> &Span<'ast> {
|
||||
match self {
|
||||
Expression::Value(expression) => &expression.span(),
|
||||
Expression::Variable(expression) => &expression.span,
|
||||
Expression::Identifier(expression) => &expression.span,
|
||||
Expression::Not(expression) => &expression.span,
|
||||
// Expression::Increment(expression) => &expression.span,
|
||||
// Expression::Decrement(expression) => &expression.span,
|
||||
@ -680,7 +697,7 @@ impl<'ast> fmt::Display for Expression<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Expression::Value(ref expression) => write!(f, "{}", expression),
|
||||
Expression::Variable(ref expression) => write!(f, "{}", expression),
|
||||
Expression::Identifier(ref expression) => write!(f, "{}", expression),
|
||||
Expression::Not(ref expression) => write!(f, "!{}", expression.expression),
|
||||
// Expression::Increment(ref expression) => write!(f, "{}++", expression.expression),
|
||||
// Expression::Decrement(ref expression) => write!(f, "{}--", expression.expression),
|
||||
@ -704,11 +721,13 @@ 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.variable)
|
||||
}
|
||||
Expression::CircuitInline(ref expression) => write!(
|
||||
f,
|
||||
"inline circuit display not impl {}",
|
||||
expression.identifier
|
||||
),
|
||||
Expression::Postfix(ref expression) => {
|
||||
write!(f, "Postfix display not impl {}", expression.variable)
|
||||
write!(f, "Postfix display not impl {}", expression.identifier)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -804,14 +823,14 @@ fn parse_term(pair: Pair<Rule>) -> Box<Expression> {
|
||||
Value::from_pest(&mut pair.into_inner().next().unwrap().into_inner()).unwrap()
|
||||
)
|
||||
},
|
||||
Rule::variable => Expression::Variable(
|
||||
Variable::from_pest(&mut pair.into_inner().next().unwrap().into_inner()).unwrap(),
|
||||
Rule::identifier => Expression::Identifier(
|
||||
Identifier::from_pest(&mut pair.into_inner().next().unwrap().into_inner()).unwrap(),
|
||||
),
|
||||
rule => unreachable!("`expression_primitive` should contain one of [`value`, `variable`], found {:#?}", rule)
|
||||
rule => unreachable!("`expression_primitive` should contain one of [`value`, `identifier`], found {:#?}", rule)
|
||||
}
|
||||
},
|
||||
|
||||
rule => unreachable!("`term` should contain one of ['value', 'variable', 'expression', 'expression_not', 'expression_increment', 'expression_decrement'], found {:#?}", rule)
|
||||
rule => unreachable!("`term` should contain one of ['value', 'identifier', 'expression', 'expression_not', 'expression_increment', 'expression_decrement'], found {:#?}", rule)
|
||||
}
|
||||
}
|
||||
rule => unreachable!(
|
||||
@ -896,7 +915,7 @@ pub struct ConditionalStatement<'ast> {
|
||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||
#[pest_ast(rule(Rule::statement_for))]
|
||||
pub struct ForStatement<'ast> {
|
||||
pub index: Variable<'ast>,
|
||||
pub index: Identifier<'ast>,
|
||||
pub start: Expression<'ast>,
|
||||
pub stop: Expression<'ast>,
|
||||
pub statements: Vec<Statement<'ast>>,
|
||||
@ -907,8 +926,8 @@ 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 function_name: Variable<'ast>,
|
||||
pub variables: Vec<Variable<'ast>>,
|
||||
pub function_name: Identifier<'ast>,
|
||||
pub arguments: Vec<Expression<'ast>>,
|
||||
#[pest_ast(outer())]
|
||||
pub span: Span<'ast>,
|
||||
@ -918,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>,
|
||||
@ -1016,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, ", ")?;
|
||||
}
|
||||
}
|
||||
@ -1028,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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1073,29 +1084,21 @@ 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())]
|
||||
pub span: Span<'ast>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||
#[pest_ast(rule(Rule::function_name))]
|
||||
pub struct FunctionName<'ast> {
|
||||
#[pest_ast(outer(with(span_into_string)))]
|
||||
pub value: String,
|
||||
#[pest_ast(outer())]
|
||||
pub span: Span<'ast>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||
#[pest_ast(rule(Rule::function_definition))]
|
||||
pub struct Function<'ast> {
|
||||
pub function_name: FunctionName<'ast>,
|
||||
pub parameters: Vec<Parameter<'ast>>,
|
||||
pub function_name: Identifier<'ast>,
|
||||
pub parameters: Vec<InputModel<'ast>>,
|
||||
pub returns: Vec<Type<'ast>>,
|
||||
pub statements: Vec<Statement<'ast>>,
|
||||
#[pest_ast(outer())]
|
||||
@ -1122,8 +1125,8 @@ pub struct ImportSource<'ast> {
|
||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||
#[pest_ast(rule(Rule::import_symbol))]
|
||||
pub struct ImportSymbol<'ast> {
|
||||
pub value: Variable<'ast>,
|
||||
pub alias: Option<Variable<'ast>>,
|
||||
pub value: Identifier<'ast>,
|
||||
pub alias: Option<Identifier<'ast>>,
|
||||
#[pest_ast(outer())]
|
||||
pub span: Span<'ast>,
|
||||
}
|
||||
@ -1143,7 +1146,7 @@ pub struct Import<'ast> {
|
||||
#[pest_ast(rule(Rule::file))]
|
||||
pub struct File<'ast> {
|
||||
pub imports: Vec<Import<'ast>>,
|
||||
pub structs: Vec<Circuit<'ast>>,
|
||||
pub circuits: Vec<Circuit<'ast>>,
|
||||
pub functions: Vec<Function<'ast>>,
|
||||
pub eoi: EOI,
|
||||
#[pest_ast(outer())]
|
||||
|
@ -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)
|
||||
})?
|
||||
|
@ -2,11 +2,11 @@
|
||||
|
||||
use crate::{
|
||||
constraints::{
|
||||
new_scope_from_variable, new_variable_from_variable, ConstrainedCircuitMember,
|
||||
new_scope_from_variable, new_variable_from_variable, ConstrainedCircuitObject,
|
||||
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 {
|
||||
@ -308,30 +308,38 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
|
||||
array: Box<Expression<F, G>>,
|
||||
index: RangeOrExpression<F, G>,
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
match self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *array)? {
|
||||
ConstrainedValue::Array(array) => {
|
||||
match index {
|
||||
RangeOrExpression::Range(from, to) => {
|
||||
let from_resolved = match from {
|
||||
Some(from_index) => from_index.to_usize(),
|
||||
None => 0usize, // Array slice starts at index 0
|
||||
};
|
||||
let to_resolved = match to {
|
||||
Some(to_index) => to_index.to_usize(),
|
||||
None => array.len(), // Array slice ends at array length
|
||||
};
|
||||
Ok(ConstrainedValue::Array(
|
||||
array[from_resolved..to_resolved].to_owned(),
|
||||
))
|
||||
}
|
||||
RangeOrExpression::Expression(index) => {
|
||||
let index_resolved =
|
||||
self.enforce_index(cs, file_scope, function_scope, index)?;
|
||||
Ok(array[index_resolved].to_owned())
|
||||
}
|
||||
}
|
||||
let array = match self.enforce_expression(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
*array,
|
||||
)? {
|
||||
ConstrainedValue::Array(array) => array,
|
||||
ConstrainedValue::Mutable(value) => match *value {
|
||||
ConstrainedValue::Array(array) => array,
|
||||
value => return Err(ExpressionError::InvalidArrayAccess(value.to_string())),
|
||||
},
|
||||
value => return Err(ExpressionError::InvalidArrayAccess(value.to_string())),
|
||||
};
|
||||
|
||||
match index {
|
||||
RangeOrExpression::Range(from, to) => {
|
||||
let from_resolved = match from {
|
||||
Some(from_index) => from_index.to_usize(),
|
||||
None => 0usize, // Array slice starts at index 0
|
||||
};
|
||||
let to_resolved = match to {
|
||||
Some(to_index) => to_index.to_usize(),
|
||||
None => array.len(), // Array slice ends at array length
|
||||
};
|
||||
Ok(ConstrainedValue::Array(
|
||||
array[from_resolved..to_resolved].to_owned(),
|
||||
))
|
||||
}
|
||||
RangeOrExpression::Expression(index) => {
|
||||
let index_resolved = self.enforce_index(cs, file_scope, function_scope, index)?;
|
||||
Ok(array[index_resolved].to_owned())
|
||||
}
|
||||
value => Err(ExpressionError::InvalidArrayAccess(value.to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
@ -340,7 +348,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 +363,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 +380,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(ConstrainedCircuitObject(member.identifier, member_value))
|
||||
}
|
||||
|
||||
Ok(ConstrainedValue::CircuitExpression(
|
||||
@ -390,21 +398,31 @@ 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) => {
|
||||
let matched_member = members
|
||||
.into_iter()
|
||||
.find(|member| member.0 == circuit_member);
|
||||
match matched_member {
|
||||
Some(member) => Ok(member.1),
|
||||
None => Err(ExpressionError::UndefinedCircuitObject(
|
||||
circuit_member.to_string(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
value => Err(ExpressionError::InvalidCircuitAccess(value.to_string())),
|
||||
let members = match self.enforce_expression(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
*circuit_variable.clone(),
|
||||
)? {
|
||||
ConstrainedValue::CircuitExpression(_name, members) => members,
|
||||
ConstrainedValue::Mutable(value) => match *value {
|
||||
ConstrainedValue::CircuitExpression(_name, members) => members,
|
||||
value => return Err(ExpressionError::InvalidCircuitAccess(value.to_string())),
|
||||
},
|
||||
value => return Err(ExpressionError::InvalidCircuitAccess(value.to_string())),
|
||||
};
|
||||
|
||||
let matched_member = members
|
||||
.into_iter()
|
||||
.find(|member| member.0 == circuit_member);
|
||||
|
||||
match matched_member {
|
||||
Some(member) => Ok(member.1),
|
||||
None => Err(ExpressionError::UndefinedCircuitObject(
|
||||
circuit_member.to_string(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
@ -413,7 +431,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 +462,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
|
||||
|
@ -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),
|
||||
|
@ -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.0);
|
||||
let resolved_function_name =
|
||||
new_scope(program_name.name.clone(), function_name.name);
|
||||
self.store(resolved_function_name, ConstrainedValue::Function(function));
|
||||
});
|
||||
|
||||
|
@ -70,7 +70,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
|
||||
None => {
|
||||
// see if the imported symbol is a function
|
||||
let matched_function = program.functions.clone().into_iter().find(
|
||||
|(function_name, _function)| symbol.symbol.name == *function_name.0,
|
||||
|(function_name, _function)| symbol.symbol.name == *function_name.name,
|
||||
);
|
||||
|
||||
match matched_function {
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
})?
|
||||
|
@ -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)
|
||||
})?
|
||||
|
@ -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)
|
||||
})?
|
||||
|
@ -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)
|
||||
})?
|
||||
|
@ -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)
|
||||
})?
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
@ -25,95 +27,46 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
|
||||
}
|
||||
}
|
||||
|
||||
fn store_assignment(
|
||||
fn mutate_array(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
assignee: Assignee<F, G>,
|
||||
return_value: &mut ConstrainedValue<F, G>,
|
||||
name: String,
|
||||
range_or_expression: RangeOrExpression<F, G>,
|
||||
new_value: ConstrainedValue<F, G>,
|
||||
) -> Result<(), StatementError> {
|
||||
match assignee {
|
||||
Assignee::Variable(name) => {
|
||||
// Store the variable in the current scope
|
||||
let definition_name = new_scope_from_variable(function_scope.clone(), &name);
|
||||
// Resolve index so we know if we are assigning to a single value or a range of values
|
||||
match range_or_expression {
|
||||
RangeOrExpression::Expression(index) => {
|
||||
let index =
|
||||
self.enforce_index(cs, file_scope.clone(), function_scope.clone(), index)?;
|
||||
|
||||
self.store(definition_name, return_value.to_owned());
|
||||
}
|
||||
Assignee::Array(array, index_expression) => {
|
||||
// Check that array exists
|
||||
let expected_array_name = self.resolve_assignee(function_scope.clone(), *array);
|
||||
|
||||
// Resolve index so we know if we are assigning to a single value or a range of values
|
||||
match index_expression {
|
||||
RangeOrExpression::Expression(index) => {
|
||||
let index = self.enforce_index(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
index,
|
||||
)?;
|
||||
|
||||
// Modify the single value of the array in place
|
||||
match self.get_mut(&expected_array_name) {
|
||||
Some(value) => match value {
|
||||
ConstrainedValue::Array(old) => {
|
||||
old[index] = return_value.to_owned();
|
||||
}
|
||||
_ => return Err(StatementError::ArrayAssignIndex),
|
||||
},
|
||||
None => {
|
||||
return Err(StatementError::UndefinedArray(expected_array_name))
|
||||
}
|
||||
}
|
||||
}
|
||||
RangeOrExpression::Range(from, to) => {
|
||||
let from_index = match from {
|
||||
Some(integer) => integer.to_usize(),
|
||||
None => 0usize,
|
||||
};
|
||||
let to_index_option = match to {
|
||||
Some(integer) => Some(integer.to_usize()),
|
||||
None => None,
|
||||
};
|
||||
|
||||
// Modify the range of values of the array in place
|
||||
match self.get_mut(&expected_array_name) {
|
||||
Some(value) => match (value, return_value) {
|
||||
(ConstrainedValue::Array(old), ConstrainedValue::Array(new)) => {
|
||||
let to_index = to_index_option.unwrap_or(old.len());
|
||||
old.splice(from_index..to_index, new.iter().cloned());
|
||||
}
|
||||
_ => return Err(StatementError::ArrayAssignRange),
|
||||
},
|
||||
None => {
|
||||
return Err(StatementError::UndefinedArray(expected_array_name))
|
||||
}
|
||||
}
|
||||
// Modify the single value of the array in place
|
||||
match self.get_mutable_variable(name)? {
|
||||
ConstrainedValue::Array(old) => {
|
||||
old[index] = new_value;
|
||||
}
|
||||
_ => return Err(StatementError::ArrayAssignIndex),
|
||||
}
|
||||
}
|
||||
Assignee::CircuitMember(circuit_variable, circuit_member) => {
|
||||
// Check that circuit exists
|
||||
let expected_circuit_name =
|
||||
self.resolve_assignee(function_scope.clone(), *circuit_variable);
|
||||
RangeOrExpression::Range(from, to) => {
|
||||
let from_index = match from {
|
||||
Some(integer) => integer.to_usize(),
|
||||
None => 0usize,
|
||||
};
|
||||
let to_index_option = match to {
|
||||
Some(integer) => Some(integer.to_usize()),
|
||||
None => None,
|
||||
};
|
||||
|
||||
match self.get_mut(&expected_circuit_name) {
|
||||
Some(ConstrainedValue::CircuitExpression(_variable, members)) => {
|
||||
// Modify the circuit member in place
|
||||
let matched_member = members
|
||||
.into_iter()
|
||||
.find(|member| member.0 == circuit_member);
|
||||
match matched_member {
|
||||
Some(mut member) => member.1 = return_value.to_owned(),
|
||||
None => {
|
||||
return Err(StatementError::UndefinedCircuitObject(
|
||||
circuit_member.to_string(),
|
||||
))
|
||||
}
|
||||
}
|
||||
// Modify the range of values of the array in place
|
||||
match (self.get_mutable_variable(name)?, new_value) {
|
||||
(ConstrainedValue::Array(old), ConstrainedValue::Array(ref new)) => {
|
||||
let to_index = to_index_option.unwrap_or(old.len());
|
||||
old.splice(from_index..to_index, new.iter().cloned());
|
||||
}
|
||||
_ => return Err(StatementError::UndefinedCircuit(expected_circuit_name)),
|
||||
_ => return Err(StatementError::ArrayAssignRange),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -121,6 +74,46 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn mutute_circuit_object(
|
||||
&mut self,
|
||||
circuit_name: String,
|
||||
object_name: Identifier<F, G>,
|
||||
new_value: ConstrainedValue<F, G>,
|
||||
) -> Result<(), StatementError> {
|
||||
match self.get_mutable_variable(circuit_name)? {
|
||||
ConstrainedValue::CircuitExpression(_variable, objects) => {
|
||||
// Modify the circuit member in place
|
||||
let matched_object = objects.into_iter().find(|object| object.0 == object_name);
|
||||
|
||||
match matched_object {
|
||||
Some(mut object) => object.1 = new_value.to_owned(),
|
||||
None => {
|
||||
return Err(StatementError::UndefinedCircuitObject(
|
||||
object_name.to_string(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => return Err(StatementError::UndefinedCircuit(object_name.to_string())),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_mutable_variable(
|
||||
&mut self,
|
||||
name: String,
|
||||
) -> Result<&mut ConstrainedValue<F, G>, StatementError> {
|
||||
// Check that assignee exists and is mutable
|
||||
Ok(match self.get_mut(&name) {
|
||||
Some(value) => match value {
|
||||
ConstrainedValue::Mutable(mutable_value) => mutable_value,
|
||||
_ => return Err(StatementError::ImmutableAssign(name)),
|
||||
},
|
||||
None => return Err(StatementError::UndefinedVariable(name)),
|
||||
})
|
||||
}
|
||||
|
||||
fn enforce_assign_statement(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
@ -129,49 +122,71 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
|
||||
assignee: Assignee<F, G>,
|
||||
expression: Expression<F, G>,
|
||||
) -> Result<(), StatementError> {
|
||||
// Check that assignee exists
|
||||
let name = self.resolve_assignee(function_scope.clone(), assignee.clone());
|
||||
// Get the name of the variable we are assigning to
|
||||
let variable_name = self.resolve_assignee(function_scope.clone(), assignee.clone());
|
||||
|
||||
match self.get(&name) {
|
||||
Some(_assignee) => {
|
||||
let result_value = &mut self.enforce_expression(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
expression,
|
||||
)?;
|
||||
// Evaluate new value
|
||||
let new_value =
|
||||
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), expression)?;
|
||||
|
||||
self.store_assignment(cs, file_scope, function_scope, assignee, result_value)
|
||||
// Mutate the old value into the new value
|
||||
match assignee {
|
||||
Assignee::Identifier(_identifier) => {
|
||||
let old_value = self.get_mutable_variable(variable_name.clone())?;
|
||||
|
||||
*old_value = new_value;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Assignee::Array(_assignee, range_or_expression) => self.mutate_array(
|
||||
cs,
|
||||
file_scope,
|
||||
function_scope,
|
||||
variable_name,
|
||||
range_or_expression,
|
||||
new_value,
|
||||
),
|
||||
Assignee::CircuitMember(_assignee, object_name) => {
|
||||
self.mutute_circuit_object(variable_name, object_name, new_value)
|
||||
}
|
||||
None => Err(StatementError::UndefinedVariable(assignee.to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
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 +194,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 +211,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 +337,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 +424,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 +442,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,
|
||||
)?;
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
use crate::{
|
||||
errors::ValueError,
|
||||
types::{Circuit, FieldElement, Function, Type, Variable},
|
||||
types::{Circuit, FieldElement, Function, Identifier, Type},
|
||||
Integer,
|
||||
};
|
||||
|
||||
@ -13,8 +13,8 @@ use snarkos_models::{
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct ConstrainedCircuitMember<F: Field + PrimeField, G: Group>(
|
||||
pub Variable<F, G>,
|
||||
pub struct ConstrainedCircuitObject<F: Field + PrimeField, G: Group>(
|
||||
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<ConstrainedCircuitObject<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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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,24 @@ 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("Cannot assign to immutable variable {}", _0)]
|
||||
ImmutableAssign(String),
|
||||
|
||||
#[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),
|
||||
|
||||
|
@ -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)]
|
||||
|
@ -1,4 +1,10 @@
|
||||
/// Visibili_type
|
||||
/// Identifiers
|
||||
protected_name = { visibility | "let" | "for"| "if" | "else" | "as" | "return" }
|
||||
|
||||
identifier = @{ ((!protected_name ~ ASCII_ALPHA) | (protected_name ~ (ASCII_ALPHANUMERIC | "_"))) ~ (ASCII_ALPHANUMERIC | "_")* }
|
||||
|
||||
|
||||
/// Visibility
|
||||
|
||||
visibility_public = { "public" }
|
||||
visibility_private = { "private" }
|
||||
@ -55,7 +61,8 @@ operation_assign = {
|
||||
operation_mul_assign | operation_div_assign | operation_pow_assign
|
||||
}
|
||||
|
||||
/// types
|
||||
/// Types
|
||||
|
||||
type_u8 = {"u8"}
|
||||
type_u16 = {"u16"}
|
||||
type_u32 = {"u32"}
|
||||
@ -73,7 +80,7 @@ type_field = {"field"}
|
||||
type_group = {"group"}
|
||||
type_bool = {"bool"}
|
||||
type_basic = { type_field | type_group | type_bool | type_integer }
|
||||
type_circuit = { variable }
|
||||
type_circuit = { identifier }
|
||||
type_array = {type_basic ~ ("[" ~ value ~ "]")+ }
|
||||
_type = {type_array | type_basic | type_circuit}
|
||||
type_list = _{(_type ~ ("," ~ _type)*)?}
|
||||
@ -86,22 +93,13 @@ value_field = { value_number ~ type_field }
|
||||
value_group = { value_number ~ type_group }
|
||||
value_boolean = { "true" | "false" }
|
||||
value = { value_field | value_group | value_boolean | value_integer }
|
||||
expression_primitive = { value | identifier }
|
||||
|
||||
/// Variables
|
||||
/// Variables + Mutability
|
||||
|
||||
// TODO: Include "import" and "conditional"
|
||||
|
||||
protected_name = { visibility | "let" | "for"| "if" | "else" | "as" | "return" }
|
||||
|
||||
// keyword = @{ "as" | "in" | "return" | "export" | "false" |
|
||||
// "def" | "in" | "return" | "circuit" | "true" }
|
||||
|
||||
variable = @{ ((!protected_name ~ ASCII_ALPHA) | (protected_name ~ (ASCII_ALPHANUMERIC | "_"))) ~ (ASCII_ALPHANUMERIC | "_")* }
|
||||
|
||||
optionally_typed_variable = { (_type ~ variable) | (variable)}
|
||||
optionally_typed_variable_tuple = _{ optionally_typed_variable ~ ("," ~ optionally_typed_variable)* }
|
||||
|
||||
expression_primitive = { value | variable }
|
||||
mutable = {"mut"}
|
||||
variable = { mutable? ~ identifier ~ (":" ~ _type)? }
|
||||
variable_tuple = _{ variable ~ ("," ~ variable)* }
|
||||
|
||||
/// Access
|
||||
|
||||
@ -113,13 +111,13 @@ range_or_expression = { range | expression }
|
||||
|
||||
access_array = { "[" ~ range_or_expression ~ "]" }
|
||||
access_call = { "(" ~ expression_tuple ~ ")" }
|
||||
access_member = { "." ~ variable }
|
||||
access_member = { "." ~ identifier }
|
||||
access = { access_array | access_call | access_member }
|
||||
|
||||
expression_postfix = { variable ~ access+ }
|
||||
expression_postfix = { identifier ~ access+ }
|
||||
|
||||
assignee_access = { access_array | access_member }
|
||||
assignee = { variable ~ assignee_access* }
|
||||
assignee = { identifier ~ assignee_access* }
|
||||
|
||||
spread = { "..." ~ expression }
|
||||
spread_or_expression = { spread | expression }
|
||||
@ -132,13 +130,13 @@ expression_array_initializer = { "[" ~ spread_or_expression ~ ";" ~ value ~ "]"
|
||||
|
||||
/// Circuits
|
||||
|
||||
circuit_object = { variable ~ ":" ~ _type }
|
||||
circuit_object = { identifier ~ ":" ~ _type }
|
||||
circuit_object_list = _{(circuit_object ~ (NEWLINE+ ~ circuit_object)*)? }
|
||||
circuit_definition = { "circuit" ~ variable ~ "{" ~ NEWLINE* ~ circuit_object_list ~ NEWLINE* ~ "}" ~ NEWLINE* }
|
||||
circuit_definition = { "circuit" ~ identifier ~ "{" ~ NEWLINE* ~ circuit_object_list ~ NEWLINE* ~ "}" ~ NEWLINE* }
|
||||
|
||||
inline_circuit_member = { variable ~ ":" ~ expression }
|
||||
inline_circuit_member = { identifier ~ ":" ~ expression }
|
||||
inline_circuit_member_list = _{(inline_circuit_member ~ ("," ~ NEWLINE* ~ inline_circuit_member)*)? ~ ","? }
|
||||
expression_inline_circuit = { variable ~ "{" ~ NEWLINE* ~ inline_circuit_member_list ~ NEWLINE* ~ "}" }
|
||||
expression_inline_circuit = { identifier ~ "{" ~ NEWLINE* ~ inline_circuit_member_list ~ NEWLINE* ~ "}" }
|
||||
|
||||
/// Conditionals
|
||||
|
||||
@ -172,11 +170,11 @@ 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 ~ ")" ~ "=" ~ variable ~ "(" ~ 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" ~ variable ~ "in" ~ expression ~ ".." ~ expression ~ "{" ~ NEWLINE* ~ statement+ ~ "}"}
|
||||
statement_for = { "for" ~ identifier ~ "in" ~ expression ~ ".." ~ expression ~ "{" ~ NEWLINE* ~ statement+ ~ "}"}
|
||||
statement_assert = {
|
||||
assert_eq
|
||||
// | assert_true |
|
||||
@ -198,11 +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_name = @{ ((!protected_name ~ ASCII_ALPHA) | (protected_name ~ (ASCII_ALPHANUMERIC | "_"))) ~ (ASCII_ALPHANUMERIC | "_")* }
|
||||
function_definition = {"function" ~ function_name ~ "(" ~ parameter_list ~ ")" ~ ("->" ~ (_type | "(" ~ type_list ~ ")"))? ~ "{" ~ NEWLINE* ~ statement* ~ NEWLINE* ~ "}" ~ NEWLINE* }
|
||||
function_definition = {"function" ~ identifier ~ "(" ~ input_model_list ~ ")" ~ ("->" ~ (_type | "(" ~ type_list ~ ")"))? ~ "{" ~ NEWLINE* ~ statement* ~ NEWLINE* ~ "}" ~ NEWLINE* }
|
||||
|
||||
/// Utilities
|
||||
|
||||
@ -213,7 +210,7 @@ LINE_END = _{";" ~ NEWLINE*}
|
||||
/// Imports
|
||||
|
||||
import_source = @{(!"\"" ~ ANY)*}
|
||||
import_symbol = { variable ~ ("as" ~ variable)? }
|
||||
import_symbol = { identifier ~ ("as" ~ identifier)? }
|
||||
import_symbol_tuple = _{ import_symbol ~ ("," ~ NEWLINE* ~ import_symbol)* }
|
||||
|
||||
import = { "from" ~ "\"" ~ import_source ~ "\"" ~ "import" ~ ("*" | ("{" ~ NEWLINE* ~ import_symbol_tuple ~ NEWLINE* ~ "}")) ~ LINE_END}
|
||||
|
@ -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,
|
||||
@ -15,15 +14,15 @@ use snarkos_models::gadgets::{
|
||||
use std::collections::HashMap;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
/// A variable in a constraint system.
|
||||
/// An identifier in the constrained program.
|
||||
#[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,14 @@ impl<F: Field + PrimeField, G: Group> Variable<F, G> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A variable that is assigned to a value in the constrained program
|
||||
#[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 +115,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 +153,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 object 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>), // (circuit name, circuit object name)
|
||||
}
|
||||
|
||||
/// Explicit integer type
|
||||
@ -179,7 +186,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 +220,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 +252,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)]
|
||||
@ -269,13 +267,9 @@ pub enum InputValue<F: Field + PrimeField, G: Group> {
|
||||
Array(Vec<InputValue<F, G>>),
|
||||
}
|
||||
|
||||
/// The given name for a defined function in the program.
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
pub struct FunctionName(pub String);
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct Function<F: Field + PrimeField, G: Group> {
|
||||
pub function_name: FunctionName,
|
||||
pub function_name: Identifier<F, G>,
|
||||
pub inputs: Vec<InputModel<F, G>>,
|
||||
pub returns: Vec<Type<F, G>>,
|
||||
pub statements: Vec<Statement<F, G>>,
|
||||
@ -283,28 +277,24 @@ pub struct Function<F: Field + PrimeField, G: Group> {
|
||||
|
||||
impl<F: Field + PrimeField, G: Group> Function<F, G> {
|
||||
pub fn get_name(&self) -> String {
|
||||
self.function_name.0.clone()
|
||||
self.function_name.name.clone()
|
||||
}
|
||||
}
|
||||
|
||||
/// 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<FunctionName, 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(),
|
||||
@ -317,11 +307,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
|
||||
}
|
||||
}
|
||||
|
@ -2,24 +2,40 @@
|
||||
|
||||
use crate::{
|
||||
Assignee, Circuit, CircuitObject, ConditionalNestedOrEnd, ConditionalStatement, Expression,
|
||||
FieldElement, Function, FunctionName, 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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -330,24 +354,6 @@ impl<F: Field + PrimeField, G: Group> fmt::Display for InputValue<F, G> {
|
||||
}
|
||||
}
|
||||
|
||||
impl FunctionName {
|
||||
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for FunctionName {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.format(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for FunctionName {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.format(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Field + PrimeField, G: Group> Function<F, G> {
|
||||
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "function {}", self.function_name)?;
|
||||
|
@ -7,25 +7,38 @@ use snarkos_models::gadgets::utilities::{
|
||||
boolean::Boolean, uint128::UInt128, uint16::UInt16, uint32::UInt32, uint64::UInt64,
|
||||
uint8::UInt8,
|
||||
};
|
||||
use std::{collections::HashMap, marker::PhantomData};
|
||||
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 {
|
||||
name: variable.value,
|
||||
_engine: PhantomData::<F>,
|
||||
_group: PhantomData::<G>,
|
||||
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::Variable<'ast>> for types::Expression<F, G> {
|
||||
fn from(variable: ast::Variable<'ast>) -> Self {
|
||||
types::Expression::Variable(types::Variable::from(variable))
|
||||
}
|
||||
}
|
||||
/// pest ast - types::Integer
|
||||
|
||||
impl<'ast> types::Integer {
|
||||
@ -268,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.variable),
|
||||
identifier: types::Identifier::from(member.identifier),
|
||||
expression: types::Expression::from(member.expression),
|
||||
}
|
||||
}
|
||||
@ -278,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.variable);
|
||||
let variable = types::Identifier::from(expression.identifier);
|
||||
let members = expression
|
||||
.members
|
||||
.into_iter()
|
||||
@ -293,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.variable));
|
||||
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
|
||||
@ -304,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
|
||||
@ -318,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.variable),
|
||||
types::Identifier::from(struct_member.identifier),
|
||||
),
|
||||
ast::Access::Array(array) => types::Expression::ArrayAccess(
|
||||
Box::new(acc),
|
||||
@ -334,7 +348,7 @@ impl<'ast, F: Field + PrimeField, G: Group> From<ast::Expression<'ast>>
|
||||
fn from(expression: ast::Expression<'ast>) -> Self {
|
||||
match expression {
|
||||
ast::Expression::Value(value) => types::Expression::from(value),
|
||||
ast::Expression::Variable(variable) => types::Expression::from(variable),
|
||||
ast::Expression::Identifier(variable) => types::Expression::from(variable),
|
||||
ast::Expression::Not(expression) => types::Expression::from(expression),
|
||||
ast::Expression::Binary(expression) => types::Expression::from(expression),
|
||||
ast::Expression::Ternary(expression) => types::Expression::from(expression),
|
||||
@ -362,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.variable));
|
||||
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
|
||||
@ -372,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.variable),
|
||||
types::Identifier::from(struct_member.identifier),
|
||||
)
|
||||
}
|
||||
ast::AssigneeAccess::Array(array) => types::Expression::ArrayAccess(
|
||||
@ -385,15 +399,15 @@ impl<'ast, F: Field + PrimeField, G: Group> From<ast::Assignee<'ast>> for types:
|
||||
|
||||
/// pest ast -> types::Assignee
|
||||
|
||||
impl<'ast, F: Field + PrimeField, G: Group> From<ast::Variable<'ast>> for types::Assignee<F, G> {
|
||||
fn from(variable: ast::Variable<'ast>) -> Self {
|
||||
types::Assignee::Variable(types::Variable::from(variable))
|
||||
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::Identifier(types::Identifier::from(variable))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, F: Field + PrimeField, G: Group> From<ast::Assignee<'ast>> for types::Assignee<F, G> {
|
||||
fn from(assignee: ast::Assignee<'ast>) -> Self {
|
||||
let variable = types::Assignee::from(assignee.variable);
|
||||
let variable = types::Assignee::from(assignee.identifier);
|
||||
|
||||
// we start with the id, and we fold the array of accesses by wrapping the current value
|
||||
assignee
|
||||
@ -406,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.variable),
|
||||
types::Identifier::from(struct_member.identifier),
|
||||
),
|
||||
})
|
||||
}
|
||||
@ -433,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),
|
||||
statement
|
||||
._type
|
||||
.map(|_type| types::Type::<F, G>::from(_type)),
|
||||
types::Variable::from(statement.variable),
|
||||
types::Expression::from(statement.expression),
|
||||
)
|
||||
}
|
||||
@ -504,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.id)))
|
||||
.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()
|
||||
@ -575,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
|
||||
@ -667,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.variable))
|
||||
types::Type::Circuit(types::Identifier::from(struct_type.identifier))
|
||||
}
|
||||
}
|
||||
|
||||
@ -688,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.variable),
|
||||
identifier: types::Identifier::from(struct_field.identifier),
|
||||
_type: types::Type::from(struct_field._type),
|
||||
}
|
||||
}
|
||||
@ -696,55 +707,43 @@ 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.variable);
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// pest ast -> types::Function
|
||||
|
||||
impl<'ast> From<ast::FunctionName<'ast>> for types::FunctionName {
|
||||
fn from(name: ast::FunctionName<'ast>) -> Self {
|
||||
types::FunctionName(name.value)
|
||||
}
|
||||
}
|
||||
|
||||
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::FunctionName::from(function_definition.function_name);
|
||||
let function_name = types::Identifier::from(function_definition.function_name);
|
||||
let parameters = function_definition
|
||||
.parameters
|
||||
.into_iter()
|
||||
@ -775,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)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -809,29 +808,25 @@ impl<'ast, F: Field + PrimeField, G: Group> types::Program<F, G> {
|
||||
let mut functions = HashMap::new();
|
||||
let mut num_parameters = 0usize;
|
||||
|
||||
file.structs.into_iter().for_each(|struct_def| {
|
||||
file.circuits.into_iter().for_each(|struct_def| {
|
||||
structs.insert(
|
||||
types::Variable::from(struct_def.variable.clone()),
|
||||
types::Identifier::from(struct_def.identifier.clone()),
|
||||
types::Circuit::from(struct_def),
|
||||
);
|
||||
});
|
||||
file.functions.into_iter().for_each(|function_def| {
|
||||
functions.insert(
|
||||
types::FunctionName::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::FunctionName("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 {
|
||||
name,
|
||||
_group: PhantomData::<G>,
|
||||
_engine: PhantomData::<F>,
|
||||
},
|
||||
name: types::Identifier::new(name),
|
||||
num_parameters,
|
||||
imports,
|
||||
circuits: structs,
|
||||
|
Loading…
Reference in New Issue
Block a user