mirror of
https://github.com/AleoHQ/leo.git
synced 2024-11-29 11:43:28 +03:00
Merge pull request #4 from AleoHQ/development
Multiple variable assignment from function return
This commit is contained in:
commit
e31d3205d2
@ -1,4 +1,10 @@
|
|||||||
function main() -> (u32) {
|
function test() -> (u32, u32) {
|
||||||
a = 1 + 1
|
return 4, 4
|
||||||
return a
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function main() -> (u32, u32) {
|
||||||
|
a, b = test()
|
||||||
|
|
||||||
|
return a, b
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -268,6 +268,21 @@ impl<'ast> fmt::Display for Variable<'ast> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, FromPest, PartialEq, Clone)]
|
||||||
|
#[pest_ast(rule(Rule::optionally_typed_variable))]
|
||||||
|
pub struct OptionallyTypedVariable<'ast> {
|
||||||
|
pub ty: Option<Type<'ast>>,
|
||||||
|
pub id: Variable<'ast>,
|
||||||
|
#[pest_ast(outer())]
|
||||||
|
pub span: Span<'ast>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ast> fmt::Display for OptionallyTypedVariable<'ast> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Access
|
// Access
|
||||||
|
|
||||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||||
@ -782,25 +797,6 @@ impl<'ast> FromPest<'ast> for Expression<'ast> {
|
|||||||
|
|
||||||
// Statements
|
// Statements
|
||||||
|
|
||||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
|
||||||
#[pest_ast(rule(Rule::statement_assign))]
|
|
||||||
pub struct AssignStatement<'ast> {
|
|
||||||
pub assignee: Assignee<'ast>,
|
|
||||||
pub expression: Expression<'ast>,
|
|
||||||
#[pest_ast(outer())]
|
|
||||||
pub span: Span<'ast>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
|
||||||
#[pest_ast(rule(Rule::statement_definition))]
|
|
||||||
pub struct DefinitionStatement<'ast> {
|
|
||||||
pub ty: Type<'ast>,
|
|
||||||
pub variable: Variable<'ast>,
|
|
||||||
pub expression: Expression<'ast>,
|
|
||||||
#[pest_ast(outer())]
|
|
||||||
pub span: Span<'ast>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||||
#[pest_ast(rule(Rule::statement_return))]
|
#[pest_ast(rule(Rule::statement_return))]
|
||||||
pub struct ReturnStatement<'ast> {
|
pub struct ReturnStatement<'ast> {
|
||||||
@ -820,25 +816,43 @@ pub struct ForStatement<'ast> {
|
|||||||
pub span: Span<'ast>,
|
pub span: Span<'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 arguments: Vec<Expression<'ast>>,
|
||||||
|
#[pest_ast(outer())]
|
||||||
|
pub span: Span<'ast>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||||
|
#[pest_ast(rule(Rule::statement_definition))]
|
||||||
|
pub struct DefinitionStatement<'ast> {
|
||||||
|
pub ty: Type<'ast>,
|
||||||
|
pub variable: Variable<'ast>,
|
||||||
|
pub expression: Expression<'ast>,
|
||||||
|
#[pest_ast(outer())]
|
||||||
|
pub span: Span<'ast>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||||
|
#[pest_ast(rule(Rule::statement_assign))]
|
||||||
|
pub struct AssignStatement<'ast> {
|
||||||
|
pub assignee: Assignee<'ast>,
|
||||||
|
pub expression: Expression<'ast>,
|
||||||
|
#[pest_ast(outer())]
|
||||||
|
pub span: Span<'ast>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||||
#[pest_ast(rule(Rule::statement))]
|
#[pest_ast(rule(Rule::statement))]
|
||||||
pub enum Statement<'ast> {
|
pub enum Statement<'ast> {
|
||||||
Assign(AssignStatement<'ast>),
|
|
||||||
Definition(DefinitionStatement<'ast>),
|
|
||||||
Return(ReturnStatement<'ast>),
|
Return(ReturnStatement<'ast>),
|
||||||
Iteration(ForStatement<'ast>),
|
Iteration(ForStatement<'ast>),
|
||||||
}
|
MultipleAssignment(MultipleAssignmentStatement<'ast>),
|
||||||
|
Definition(DefinitionStatement<'ast>),
|
||||||
impl<'ast> fmt::Display for AssignStatement<'ast> {
|
Assign(AssignStatement<'ast>),
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "{} = {}", self.assignee, self.expression)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ast> fmt::Display for DefinitionStatement<'ast> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "{} {} = {}", self.ty, self.variable, self.expression)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast> fmt::Display for ReturnStatement<'ast> {
|
impl<'ast> fmt::Display for ReturnStatement<'ast> {
|
||||||
@ -863,13 +877,38 @@ 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() {
|
||||||
|
write!(f, "{}", id)?;
|
||||||
|
if i < self.assignees.len() - 1 {
|
||||||
|
write!(f, ", ")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write!(f, " = {}", self.function_name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ast> fmt::Display for DefinitionStatement<'ast> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{} {} = {}", self.ty, self.variable, self.expression)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ast> fmt::Display for AssignStatement<'ast> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{} = {}", self.assignee, self.expression)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'ast> fmt::Display for Statement<'ast> {
|
impl<'ast> fmt::Display for Statement<'ast> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
Statement::Assign(ref statement) => write!(f, "{}", statement),
|
|
||||||
Statement::Definition(ref statement) => write!(f, "{}", statement),
|
|
||||||
Statement::Return(ref statement) => write!(f, "{}", statement),
|
Statement::Return(ref statement) => write!(f, "{}", statement),
|
||||||
Statement::Iteration(ref statement) => write!(f, "{}", statement),
|
Statement::Iteration(ref statement) => write!(f, "{}", statement),
|
||||||
|
Statement::MultipleAssignment(ref statement) => write!(f, "{}", statement),
|
||||||
|
Statement::Assign(ref statement) => write!(f, "{}", statement),
|
||||||
|
Statement::Definition(ref statement) => write!(f, "{}", statement),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,14 +90,21 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
|||||||
.clone()
|
.clone()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.for_each(|statement| match statement {
|
.for_each(|statement| match statement {
|
||||||
Statement::Definition(variable, expression) => {
|
Statement::Return(expressions) => {
|
||||||
self.enforce_definition_statement(
|
return_values = self.enforce_return_statement(
|
||||||
cs,
|
cs,
|
||||||
function.get_name(),
|
function.get_name(),
|
||||||
variable,
|
expressions,
|
||||||
expression,
|
function.returns.to_owned(),
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
Statement::MultipleDefinition(assignees, function_call) => self
|
||||||
|
.enforce_multiple_definition_statement(
|
||||||
|
cs,
|
||||||
|
function.get_name(),
|
||||||
|
assignees,
|
||||||
|
function_call,
|
||||||
|
),
|
||||||
Statement::For(index, start, stop, statements) => {
|
Statement::For(index, start, stop, statements) => {
|
||||||
self.enforce_for_statement(
|
self.enforce_for_statement(
|
||||||
cs,
|
cs,
|
||||||
@ -108,13 +115,13 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
|||||||
statements,
|
statements,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Statement::Return(expressions) => {
|
Statement::Definition(variable, expression) => {
|
||||||
return_values = self.enforce_return_statement(
|
self.enforce_definition_statement(
|
||||||
cs,
|
cs,
|
||||||
function.get_name(),
|
function.get_name(),
|
||||||
expressions,
|
variable,
|
||||||
function.returns.to_owned(),
|
expression,
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
//! Methods to enforce constraints on expressions in a resolved aleo program.
|
//! Methods to enforce constraints on expressions in a resolved aleo program.
|
||||||
|
|
||||||
use crate::constraints::{new_scope_from_variable, ResolvedProgram, ResolvedValue};
|
use crate::constraints::{new_scope_from_variable, ResolvedProgram, ResolvedValue};
|
||||||
use crate::{Expression, RangeOrExpression, SpreadOrExpression, StructMember, Variable};
|
use crate::{
|
||||||
|
Expression, RangeOrExpression, ResolvedStructMember, SpreadOrExpression, StructMember, Variable,
|
||||||
|
};
|
||||||
|
|
||||||
use snarkos_models::curves::{Field, PrimeField};
|
use snarkos_models::curves::{Field, PrimeField};
|
||||||
use snarkos_models::gadgets::r1cs::ConstraintSystem;
|
use snarkos_models::gadgets::r1cs::ConstraintSystem;
|
||||||
@ -221,22 +223,24 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
|||||||
if let Some(resolved_value) = self.get_mut_variable(&variable) {
|
if let Some(resolved_value) = self.get_mut_variable(&variable) {
|
||||||
match resolved_value {
|
match resolved_value {
|
||||||
ResolvedValue::StructDefinition(struct_definition) => {
|
ResolvedValue::StructDefinition(struct_definition) => {
|
||||||
struct_definition
|
let resolved_members = struct_definition
|
||||||
.fields
|
.fields
|
||||||
.clone()
|
.clone()
|
||||||
.iter()
|
.iter()
|
||||||
.zip(members.clone().into_iter())
|
.zip(members.clone().into_iter())
|
||||||
.for_each(|(field, member)| {
|
.map(|(field, member)| {
|
||||||
if field.variable != member.variable {
|
if field.variable != member.variable {
|
||||||
unimplemented!("struct field variables do not match")
|
unimplemented!("struct field variables do not match")
|
||||||
}
|
}
|
||||||
// Resolve and possibly enforce struct fields
|
// Resolve and enforce struct fields
|
||||||
// do we need to store the results here?
|
let member_value =
|
||||||
let _result =
|
|
||||||
self.enforce_expression(cs, scope.clone(), member.expression);
|
self.enforce_expression(cs, scope.clone(), member.expression);
|
||||||
});
|
|
||||||
|
|
||||||
ResolvedValue::StructExpression(variable, members)
|
ResolvedStructMember(member.variable, member_value)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
ResolvedValue::StructExpression(variable, resolved_members)
|
||||||
}
|
}
|
||||||
_ => unimplemented!("Inline struct type is not defined as a struct"),
|
_ => unimplemented!("Inline struct type is not defined as a struct"),
|
||||||
}
|
}
|
||||||
@ -254,11 +258,9 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
|||||||
) -> ResolvedValue<F> {
|
) -> ResolvedValue<F> {
|
||||||
match self.enforce_expression(cs, scope.clone(), *struct_variable) {
|
match self.enforce_expression(cs, scope.clone(), *struct_variable) {
|
||||||
ResolvedValue::StructExpression(_name, members) => {
|
ResolvedValue::StructExpression(_name, members) => {
|
||||||
let matched_member = members
|
let matched_member = members.into_iter().find(|member| member.0 == struct_member);
|
||||||
.into_iter()
|
|
||||||
.find(|member| member.variable == struct_member);
|
|
||||||
match matched_member {
|
match matched_member {
|
||||||
Some(member) => self.enforce_expression(cs, scope.clone(), member.expression),
|
Some(member) => member.1,
|
||||||
None => unimplemented!("Cannot access struct member {}", struct_member.name),
|
None => unimplemented!("Cannot access struct member {}", struct_member.name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -269,13 +271,17 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
|||||||
fn enforce_function_access_expression(
|
fn enforce_function_access_expression(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
scope: String,
|
function: &Variable<F>,
|
||||||
function: Box<Expression<F>>,
|
|
||||||
arguments: Vec<Expression<F>>,
|
arguments: Vec<Expression<F>>,
|
||||||
) -> ResolvedValue<F> {
|
) -> ResolvedValue<F> {
|
||||||
match self.enforce_expression(cs, scope, *function) {
|
match self.get_mut_variable(function) {
|
||||||
ResolvedValue::Function(function) => self.enforce_function(cs, function, arguments),
|
Some(value) => match value.clone() {
|
||||||
value => unimplemented!("Cannot call unknown function {}", value),
|
ResolvedValue::Function(function) => {
|
||||||
|
self.enforce_function(cs, function.to_owned(), arguments)
|
||||||
|
}
|
||||||
|
value => unimplemented!("Cannot make function call to {}", value),
|
||||||
|
},
|
||||||
|
None => unimplemented!("Cannot call unknown function {}", function),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,7 +399,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
|||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
Expression::FunctionCall(function, arguments) => {
|
Expression::FunctionCall(function, arguments) => {
|
||||||
self.enforce_function_access_expression(cs, scope, function, arguments)
|
self.enforce_function_access_expression(cs, &function, arguments)
|
||||||
} // _ => unimplemented!(),
|
} // _ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! The in memory stored value for a defined name in a resolved aleo program.
|
//! The in memory stored value for a defined name in a resolved aleo program.
|
||||||
|
|
||||||
use crate::types::{Function, Struct, StructMember, Type, Variable};
|
use crate::types::{Function, Struct, Type, Variable};
|
||||||
|
|
||||||
use snarkos_models::curves::{Field, PrimeField};
|
use snarkos_models::curves::{Field, PrimeField};
|
||||||
use snarkos_models::gadgets::{utilities::boolean::Boolean, utilities::uint32::UInt32};
|
use snarkos_models::gadgets::{utilities::boolean::Boolean, utilities::uint32::UInt32};
|
||||||
@ -13,11 +13,14 @@ pub enum ResolvedValue<F: Field + PrimeField> {
|
|||||||
Boolean(Boolean),
|
Boolean(Boolean),
|
||||||
Array(Vec<ResolvedValue<F>>),
|
Array(Vec<ResolvedValue<F>>),
|
||||||
StructDefinition(Struct<F>),
|
StructDefinition(Struct<F>),
|
||||||
StructExpression(Variable<F>, Vec<StructMember<F>>),
|
StructExpression(Variable<F>, Vec<ResolvedStructMember<F>>),
|
||||||
Function(Function<F>),
|
Function(Function<F>),
|
||||||
Return(Vec<ResolvedValue<F>>), // add Null for function returns
|
Return(Vec<ResolvedValue<F>>), // add Null for function returns
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ResolvedStructMember<F: Field + PrimeField>(pub Variable<F>, pub ResolvedValue<F>);
|
||||||
|
|
||||||
impl<F: Field + PrimeField> ResolvedValue<F> {
|
impl<F: Field + PrimeField> ResolvedValue<F> {
|
||||||
pub(crate) fn match_type(&self, ty: &Type<F>) -> bool {
|
pub(crate) fn match_type(&self, ty: &Type<F>) -> bool {
|
||||||
match (self, ty) {
|
match (self, ty) {
|
||||||
@ -60,7 +63,7 @@ impl<F: Field + PrimeField> fmt::Display for ResolvedValue<F> {
|
|||||||
ResolvedValue::StructExpression(ref variable, ref members) => {
|
ResolvedValue::StructExpression(ref variable, ref members) => {
|
||||||
write!(f, "{} {{", variable)?;
|
write!(f, "{} {{", variable)?;
|
||||||
for (i, member) in members.iter().enumerate() {
|
for (i, member) in members.iter().enumerate() {
|
||||||
write!(f, "{}: {}", member.variable, member.expression)?;
|
write!(f, "{}: {}", member.0, member.1)?;
|
||||||
if i < members.len() - 1 {
|
if i < members.len() - 1 {
|
||||||
write!(f, ", ")?;
|
write!(f, ", ")?;
|
||||||
}
|
}
|
||||||
|
@ -17,28 +17,21 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn enforce_definition_statement(
|
fn enforce_definition(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
scope: String,
|
scope: String,
|
||||||
assignee: Assignee<F>,
|
assignee: Assignee<F>,
|
||||||
expression: Expression<F>,
|
return_value: &mut ResolvedValue<F>,
|
||||||
) {
|
) {
|
||||||
// Create or modify the lhs variable in the current function scope
|
|
||||||
match assignee {
|
match assignee {
|
||||||
Assignee::Variable(name) => {
|
Assignee::Variable(name) => {
|
||||||
// Store the variable in the current scope
|
// Store the variable in the current scope
|
||||||
let definition_name = new_scope_from_variable(scope.clone(), &name);
|
let definition_name = new_scope_from_variable(scope.clone(), &name);
|
||||||
|
|
||||||
// Evaluate the rhs expression in the current function scope
|
self.store(definition_name, return_value.to_owned());
|
||||||
let result = self.enforce_expression(cs, scope, expression);
|
|
||||||
|
|
||||||
self.store(definition_name, result);
|
|
||||||
}
|
}
|
||||||
Assignee::Array(array, index_expression) => {
|
Assignee::Array(array, index_expression) => {
|
||||||
// Evaluate the rhs expression in the current function scope
|
|
||||||
let result = &mut self.enforce_expression(cs, scope.clone(), expression);
|
|
||||||
|
|
||||||
// Check that array exists
|
// Check that array exists
|
||||||
let expected_array_name = self.resolve_assignee(scope.clone(), *array);
|
let expected_array_name = self.resolve_assignee(scope.clone(), *array);
|
||||||
|
|
||||||
@ -51,7 +44,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
|||||||
match self.get_mut(&expected_array_name) {
|
match self.get_mut(&expected_array_name) {
|
||||||
Some(value) => match value {
|
Some(value) => match value {
|
||||||
ResolvedValue::Array(old) => {
|
ResolvedValue::Array(old) => {
|
||||||
old[index] = result.to_owned();
|
old[index] = return_value.to_owned();
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
unimplemented!("Cannot assign single index to array of values ")
|
unimplemented!("Cannot assign single index to array of values ")
|
||||||
@ -75,7 +68,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
|||||||
|
|
||||||
// Modify the range of values of the array in place
|
// Modify the range of values of the array in place
|
||||||
match self.get_mut(&expected_array_name) {
|
match self.get_mut(&expected_array_name) {
|
||||||
Some(value) => match (value, result) {
|
Some(value) => match (value, return_value) {
|
||||||
(ResolvedValue::Array(old), ResolvedValue::Array(new)) => {
|
(ResolvedValue::Array(old), ResolvedValue::Array(new)) => {
|
||||||
let to_index = to_index_option.unwrap_or(old.len());
|
let to_index = to_index_option.unwrap_or(old.len());
|
||||||
old.splice(from_index..to_index, new.iter().cloned());
|
old.splice(from_index..to_index, new.iter().cloned());
|
||||||
@ -100,11 +93,10 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
|||||||
Some(value) => match value {
|
Some(value) => match value {
|
||||||
ResolvedValue::StructExpression(_variable, members) => {
|
ResolvedValue::StructExpression(_variable, members) => {
|
||||||
// Modify the struct member in place
|
// Modify the struct member in place
|
||||||
let matched_member = members
|
let matched_member =
|
||||||
.into_iter()
|
members.into_iter().find(|member| member.0 == struct_member);
|
||||||
.find(|member| member.variable == struct_member);
|
|
||||||
match matched_member {
|
match matched_member {
|
||||||
Some(mut member) => member.expression = expression,
|
Some(mut member) => member.1 = return_value.to_owned(),
|
||||||
None => unimplemented!(
|
None => unimplemented!(
|
||||||
"struct member {} does not exist in {}",
|
"struct member {} does not exist in {}",
|
||||||
struct_member,
|
struct_member,
|
||||||
@ -122,7 +114,43 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn enforce_definition_statement(
|
||||||
|
&mut self,
|
||||||
|
cs: &mut CS,
|
||||||
|
scope: String,
|
||||||
|
assignee: Assignee<F>,
|
||||||
|
expression: Expression<F>,
|
||||||
|
) {
|
||||||
|
let result_value = &mut self.enforce_expression(cs, scope.clone(), expression);
|
||||||
|
|
||||||
|
self.enforce_definition(cs, scope, assignee, result_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn enforce_multiple_definition_statement(
|
||||||
|
&mut self,
|
||||||
|
cs: &mut CS,
|
||||||
|
scope: String,
|
||||||
|
assignees: Vec<Assignee<F>>,
|
||||||
|
function: Expression<F>,
|
||||||
|
) {
|
||||||
|
// Expect return values from function
|
||||||
|
let return_values = match self.enforce_expression(cs, scope.clone(), function) {
|
||||||
|
ResolvedValue::Return(values) => values,
|
||||||
|
value => unimplemented!(
|
||||||
|
"multiple assignment only implemented for functions, got {}",
|
||||||
|
value
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
assignees
|
||||||
|
.into_iter()
|
||||||
|
.zip(return_values.into_iter())
|
||||||
|
.for_each(|(assignee, mut return_value)| {
|
||||||
|
self.enforce_definition(cs, scope.clone(), assignee, &mut return_value);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn enforce_return_statement(
|
pub(crate) fn enforce_return_statement(
|
||||||
@ -156,15 +184,18 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
|||||||
return_types: Vec<Type<F>>,
|
return_types: Vec<Type<F>>,
|
||||||
) {
|
) {
|
||||||
match statement {
|
match statement {
|
||||||
Statement::Definition(variable, expression) => {
|
Statement::Return(statements) => {
|
||||||
self.enforce_definition_statement(cs, scope, variable, expression);
|
// TODO: add support for early termination
|
||||||
|
let _res = self.enforce_return_statement(cs, scope, statements, return_types);
|
||||||
}
|
}
|
||||||
Statement::For(index, start, stop, statements) => {
|
Statement::For(index, start, stop, statements) => {
|
||||||
self.enforce_for_statement(cs, scope, index, start, stop, statements);
|
self.enforce_for_statement(cs, scope, index, start, stop, statements);
|
||||||
}
|
}
|
||||||
Statement::Return(statements) => {
|
Statement::MultipleDefinition(assignees, function) => {
|
||||||
// TODO: add support for early termination
|
self.enforce_multiple_definition_statement(cs, scope, assignees, function);
|
||||||
let _res = self.enforce_return_statement(cs, scope, statements, return_types);
|
}
|
||||||
|
Statement::Definition(variable, expression) => {
|
||||||
|
self.enforce_definition_statement(cs, scope, variable, expression);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -76,6 +76,8 @@ protected_name = { visibility | value_boolean | "return" }
|
|||||||
// "def" | "in" | "return" | "struct" | "true" }
|
// "def" | "in" | "return" | "struct" | "true" }
|
||||||
|
|
||||||
variable = @{ ((!protected_name ~ ASCII_ALPHA) | (protected_name ~ (ASCII_ALPHANUMERIC | "_"))) ~ (ASCII_ALPHANUMERIC | "_")* }
|
variable = @{ ((!protected_name ~ ASCII_ALPHA) | (protected_name ~ (ASCII_ALPHANUMERIC | "_"))) ~ (ASCII_ALPHANUMERIC | "_")* }
|
||||||
|
optionally_typed_variable = { (variable) | (ty ~ variable) }
|
||||||
|
optionally_typed_variable_tuple = _{ optionally_typed_variable ~ ("," ~ optionally_typed_variable)* }
|
||||||
expression_primitive = { value | variable }
|
expression_primitive = { value | variable }
|
||||||
|
|
||||||
/// Access
|
/// Access
|
||||||
@ -139,14 +141,16 @@ expression_tuple = _{ (expression ~ ("," ~ expression)*)? }
|
|||||||
|
|
||||||
/// Statements
|
/// Statements
|
||||||
|
|
||||||
statement_assign = { assignee ~ "=" ~ expression }
|
|
||||||
statement_definition = { ty ~ variable ~ "=" ~ expression }
|
|
||||||
statement_return = { "return" ~ expression_tuple }
|
statement_return = { "return" ~ expression_tuple }
|
||||||
statement_for = { "for" ~ variable ~ "in" ~ expression ~ ".." ~ expression ~ "do" ~ NEWLINE* ~ statement* ~ "endfor"}
|
statement_for = { "for" ~ variable ~ "in" ~ expression ~ ".." ~ expression ~ "do" ~ NEWLINE* ~ statement* ~ "endfor"}
|
||||||
|
statement_multiple_assignment = { optionally_typed_variable_tuple ~ "=" ~ variable ~ "(" ~ expression_tuple ~ ")" }
|
||||||
|
statement_definition = { ty ~ variable ~ "=" ~ expression }
|
||||||
|
statement_assign = { assignee ~ "=" ~ expression }
|
||||||
|
|
||||||
statement = {
|
statement = {
|
||||||
(statement_return
|
(statement_return
|
||||||
| (statement_for
|
| (statement_for
|
||||||
|
| statement_multiple_assignment
|
||||||
| statement_definition
|
| statement_definition
|
||||||
| statement_assign
|
| statement_assign
|
||||||
) ~ NEWLINE
|
) ~ NEWLINE
|
||||||
@ -159,7 +163,7 @@ parameter = {variable ~ ":" ~ visibility? ~ ty}
|
|||||||
parameter_list = _{(parameter ~ ("," ~ parameter)*)?}
|
parameter_list = _{(parameter ~ ("," ~ parameter)*)?}
|
||||||
|
|
||||||
function_name = @{ ((!protected_name ~ ASCII_ALPHA) | (protected_name ~ (ASCII_ALPHANUMERIC | "_"))) ~ (ASCII_ALPHANUMERIC | "_")* }
|
function_name = @{ ((!protected_name ~ ASCII_ALPHA) | (protected_name ~ (ASCII_ALPHANUMERIC | "_"))) ~ (ASCII_ALPHANUMERIC | "_")* }
|
||||||
function_definition = {"function" ~ function_name ~ "(" ~ parameter_list ~ ")" ~ "->" ~ "(" ~ type_list ~ ")" ~ "{" ~ NEWLINE* ~ statement* ~ "}"}
|
function_definition = {"function" ~ function_name ~ "(" ~ parameter_list ~ ")" ~ "->" ~ "(" ~ type_list ~ ")" ~ "{" ~ NEWLINE* ~ statement* ~ NEWLINE* ~ "}" ~ NEWLINE* }
|
||||||
|
|
||||||
/// Utilities
|
/// Utilities
|
||||||
|
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
//! Module containing structs and types that make up an Leo program.
|
//! Module containing structs and types that make up an Leo program.
|
||||||
|
|
||||||
extern crate from_pest;
|
extern crate from_pest;
|
||||||
#[macro_use] extern crate lazy_static;
|
#[macro_use]
|
||||||
|
extern crate lazy_static;
|
||||||
extern crate pest;
|
extern crate pest;
|
||||||
extern crate pest_ast;
|
extern crate pest_ast;
|
||||||
#[macro_use] extern crate pest_derive;
|
#[macro_use]
|
||||||
|
extern crate pest_derive;
|
||||||
|
|
||||||
pub mod ast;
|
pub mod ast;
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ pub enum Expression<F: Field + PrimeField> {
|
|||||||
StructMemberAccess(Box<Expression<F>>, Variable<F>), // (struct name, struct member name)
|
StructMemberAccess(Box<Expression<F>>, Variable<F>), // (struct name, struct member name)
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
FunctionCall(Box<Expression<F>>, Vec<Expression<F>>),
|
FunctionCall(Variable<F>, Vec<Expression<F>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Definition assignee: v, arr[0..2], Point p.x
|
/// Definition assignee: v, arr[0..2], Point p.x
|
||||||
@ -101,9 +101,10 @@ pub enum Assignee<F: Field + PrimeField> {
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum Statement<F: Field + PrimeField> {
|
pub enum Statement<F: Field + PrimeField> {
|
||||||
// Declaration(Variable),
|
// Declaration(Variable),
|
||||||
|
Return(Vec<Expression<F>>),
|
||||||
Definition(Assignee<F>, Expression<F>),
|
Definition(Assignee<F>, Expression<F>),
|
||||||
For(Variable<F>, Integer, Integer, Vec<Statement<F>>),
|
For(Variable<F>, Integer, Integer, Vec<Statement<F>>),
|
||||||
Return(Vec<Expression<F>>),
|
MultipleDefinition(Vec<Assignee<F>>, Expression<F>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Explicit type used for defining struct members and function parameters
|
/// Explicit type used for defining struct members and function parameters
|
||||||
|
@ -141,8 +141,24 @@ impl<F: Field + PrimeField> fmt::Display for Assignee<F> {
|
|||||||
impl<F: Field + PrimeField> fmt::Display for Statement<F> {
|
impl<F: Field + PrimeField> fmt::Display for Statement<F> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
Statement::Definition(ref variable, ref statement) => {
|
Statement::Return(ref statements) => {
|
||||||
write!(f, "{} = {}", variable, statement)
|
write!(f, "return ")?;
|
||||||
|
for (i, value) in statements.iter().enumerate() {
|
||||||
|
write!(f, "{}", value)?;
|
||||||
|
if i < statements.len() - 1 {
|
||||||
|
write!(f, ", ")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write!(f, "\n")
|
||||||
|
}
|
||||||
|
Statement::MultipleDefinition(ref assignees, ref function) => {
|
||||||
|
for (i, id) in assignees.iter().enumerate() {
|
||||||
|
write!(f, "{}", id)?;
|
||||||
|
if i < assignees.len() - 1 {
|
||||||
|
write!(f, ", ")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write!(f, " = {}", function)
|
||||||
}
|
}
|
||||||
Statement::For(ref var, ref start, ref stop, ref list) => {
|
Statement::For(ref var, ref start, ref stop, ref list) => {
|
||||||
write!(f, "for {} in {}..{} do\n", var, start, stop)?;
|
write!(f, "for {} in {}..{} do\n", var, start, stop)?;
|
||||||
@ -151,11 +167,8 @@ impl<F: Field + PrimeField> fmt::Display for Statement<F> {
|
|||||||
}
|
}
|
||||||
write!(f, "\tendfor")
|
write!(f, "\tendfor")
|
||||||
}
|
}
|
||||||
Statement::Return(ref statements) => {
|
Statement::Definition(ref variable, ref statement) => {
|
||||||
statements.iter().for_each(|statement| {
|
write!(f, "{} = {}", variable, statement)
|
||||||
write!(f, "return {}", statement).unwrap();
|
|
||||||
});
|
|
||||||
write!(f, "\n")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -164,8 +177,24 @@ impl<F: Field + PrimeField> fmt::Display for Statement<F> {
|
|||||||
impl<F: Field + PrimeField> fmt::Debug for Statement<F> {
|
impl<F: Field + PrimeField> fmt::Debug for Statement<F> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
Statement::Definition(ref variable, ref statement) => {
|
Statement::Return(ref statements) => {
|
||||||
write!(f, "{} = {}", variable, statement)
|
write!(f, "return ")?;
|
||||||
|
for (i, value) in statements.iter().enumerate() {
|
||||||
|
write!(f, "{}", value)?;
|
||||||
|
if i < statements.len() - 1 {
|
||||||
|
write!(f, ", ")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write!(f, "\n")
|
||||||
|
}
|
||||||
|
Statement::MultipleDefinition(ref assignees, ref function) => {
|
||||||
|
for (i, id) in assignees.iter().enumerate() {
|
||||||
|
write!(f, "{}", id)?;
|
||||||
|
if i < assignees.len() - 1 {
|
||||||
|
write!(f, ", ")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write!(f, " = {}()", function)
|
||||||
}
|
}
|
||||||
Statement::For(ref var, ref start, ref stop, ref list) => {
|
Statement::For(ref var, ref start, ref stop, ref list) => {
|
||||||
write!(f, "for {:?} in {:?}..{:?} do\n", var, start, stop)?;
|
write!(f, "for {:?} in {:?}..{:?} do\n", var, start, stop)?;
|
||||||
@ -174,11 +203,8 @@ impl<F: Field + PrimeField> fmt::Debug for Statement<F> {
|
|||||||
}
|
}
|
||||||
write!(f, "\tendfor")
|
write!(f, "\tendfor")
|
||||||
}
|
}
|
||||||
Statement::Return(ref statements) => {
|
Statement::Definition(ref variable, ref statement) => {
|
||||||
statements.iter().for_each(|statement| {
|
write!(f, "{} = {}", variable, statement)
|
||||||
write!(f, "return {}", statement).unwrap();
|
|
||||||
});
|
|
||||||
write!(f, "\n")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -205,8 +205,8 @@ impl<'ast, F: Field + PrimeField> From<ast::PostfixExpression<'ast>> for types::
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.fold(variable, |acc, access| match access {
|
.fold(variable, |acc, access| match access {
|
||||||
ast::Access::Call(function) => match acc {
|
ast::Access::Call(function) => match acc {
|
||||||
types::Expression::Variable(_) => types::Expression::FunctionCall(
|
types::Expression::Variable(variable) => types::Expression::FunctionCall(
|
||||||
Box::new(acc),
|
variable,
|
||||||
function
|
function
|
||||||
.expressions
|
.expressions
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -345,24 +345,6 @@ impl<'ast, F: Field + PrimeField> From<ast::Assignee<'ast>> for types::Assignee<
|
|||||||
|
|
||||||
/// pest ast -> types::Statement
|
/// pest ast -> types::Statement
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::AssignStatement<'ast>> for types::Statement<F> {
|
|
||||||
fn from(statement: ast::AssignStatement<'ast>) -> Self {
|
|
||||||
types::Statement::Definition(
|
|
||||||
types::Assignee::from(statement.assignee),
|
|
||||||
types::Expression::from(statement.expression),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::DefinitionStatement<'ast>> for types::Statement<F> {
|
|
||||||
fn from(statement: ast::DefinitionStatement<'ast>) -> Self {
|
|
||||||
types::Statement::Definition(
|
|
||||||
types::Assignee::from(statement.variable),
|
|
||||||
types::Expression::from_type(statement.ty, statement.expression),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::ReturnStatement<'ast>> for types::Statement<F> {
|
impl<'ast, F: Field + PrimeField> From<ast::ReturnStatement<'ast>> for types::Statement<F> {
|
||||||
fn from(statement: ast::ReturnStatement<'ast>) -> Self {
|
fn from(statement: ast::ReturnStatement<'ast>) -> Self {
|
||||||
types::Statement::Return(
|
types::Statement::Return(
|
||||||
@ -399,13 +381,56 @@ impl<'ast, F: Field + PrimeField> From<ast::ForStatement<'ast>> for types::State
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'ast, F: Field + PrimeField> From<ast::MultipleAssignmentStatement<'ast>>
|
||||||
|
for types::Statement<F>
|
||||||
|
{
|
||||||
|
fn from(statement: ast::MultipleAssignmentStatement<'ast>) -> Self {
|
||||||
|
let assignees = statement
|
||||||
|
.assignees
|
||||||
|
.into_iter()
|
||||||
|
.map(|i| types::Assignee::Variable(types::Variable::from(i.id)))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
types::Statement::MultipleDefinition(
|
||||||
|
assignees,
|
||||||
|
types::Expression::FunctionCall(
|
||||||
|
types::Variable::from(statement.function_name),
|
||||||
|
statement
|
||||||
|
.arguments
|
||||||
|
.into_iter()
|
||||||
|
.map(|e| types::Expression::from(e))
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ast, F: Field + PrimeField> From<ast::AssignStatement<'ast>> for types::Statement<F> {
|
||||||
|
fn from(statement: ast::AssignStatement<'ast>) -> Self {
|
||||||
|
types::Statement::Definition(
|
||||||
|
types::Assignee::from(statement.assignee),
|
||||||
|
types::Expression::from(statement.expression),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ast, F: Field + PrimeField> From<ast::DefinitionStatement<'ast>> for types::Statement<F> {
|
||||||
|
fn from(statement: ast::DefinitionStatement<'ast>) -> Self {
|
||||||
|
types::Statement::Definition(
|
||||||
|
types::Assignee::from(statement.variable),
|
||||||
|
types::Expression::from_type(statement.ty, statement.expression),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::Statement<'ast>> for types::Statement<F> {
|
impl<'ast, F: Field + PrimeField> From<ast::Statement<'ast>> for types::Statement<F> {
|
||||||
fn from(statement: ast::Statement<'ast>) -> Self {
|
fn from(statement: ast::Statement<'ast>) -> Self {
|
||||||
match statement {
|
match statement {
|
||||||
|
ast::Statement::Return(statement) => types::Statement::from(statement),
|
||||||
|
ast::Statement::Iteration(statement) => types::Statement::from(statement),
|
||||||
|
ast::Statement::MultipleAssignment(statement) => types::Statement::from(statement),
|
||||||
ast::Statement::Assign(statement) => types::Statement::from(statement),
|
ast::Statement::Assign(statement) => types::Statement::from(statement),
|
||||||
ast::Statement::Definition(statement) => types::Statement::from(statement),
|
ast::Statement::Definition(statement) => types::Statement::from(statement),
|
||||||
ast::Statement::Iteration(statement) => types::Statement::from(statement),
|
|
||||||
ast::Statement::Return(statement) => types::Statement::from(statement),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user