Merge branch 'master' of https://github.com/AleoHQ/language into feature/compiler

This commit is contained in:
howardwu 2020-04-26 22:29:22 -07:00
commit 85eb6cf6a8
15 changed files with 855 additions and 405 deletions

View File

@ -1,4 +1,4 @@
function main() -> (u32) {
a = 1 + 1
return a
function main(a: private u32) -> (u32) {
b = a + 5;
return a
}

View File

@ -1,4 +1,8 @@
struct Point {
u32 x
u32 y
}
}
function test() -> (u32) {
return 5
}

View File

@ -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
#[derive(Clone, Debug, FromPest, PartialEq)]
@ -782,25 +797,6 @@ impl<'ast> FromPest<'ast> for Expression<'ast> {
// 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)]
#[pest_ast(rule(Rule::statement_return))]
pub struct ReturnStatement<'ast> {
@ -820,25 +816,43 @@ pub struct ForStatement<'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)]
#[pest_ast(rule(Rule::statement))]
pub enum Statement<'ast> {
Assign(AssignStatement<'ast>),
Definition(DefinitionStatement<'ast>),
Return(ReturnStatement<'ast>),
Iteration(ForStatement<'ast>),
}
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 DefinitionStatement<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {} = {}", self.ty, self.variable, self.expression)
}
MultipleAssignment(MultipleAssignmentStatement<'ast>),
Definition(DefinitionStatement<'ast>),
Assign(AssignStatement<'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> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Statement::Assign(ref statement) => write!(f, "{}", statement),
Statement::Definition(ref statement) => write!(f, "{}", statement),
Statement::Return(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),
}
}
}
@ -924,19 +963,9 @@ pub struct ImportSource<'ast> {
}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::main_import))]
pub struct MainImport<'ast> {
pub source: ImportSource<'ast>,
pub alias: Option<Variable<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::from_import))]
pub struct FromImport<'ast> {
pub source: ImportSource<'ast>,
pub symbol: Variable<'ast>,
#[pest_ast(rule(Rule::import_symbol))]
pub struct ImportSymbol<'ast> {
pub value: Variable<'ast>,
pub alias: Option<Variable<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
@ -944,9 +973,11 @@ pub struct FromImport<'ast> {
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::import))]
pub enum Import<'ast> {
Main(MainImport<'ast>),
From(FromImport<'ast>),
pub struct Import<'ast> {
pub source: ImportSource<'ast>,
pub symbols: Vec<ImportSymbol<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
// File

View File

@ -1,7 +1,9 @@
//! Methods to enforce constraints a resolved aleo program.
//! Methods to enforce constraints and construct a resolved aleo program.
use crate::ast;
use crate::constraints::{new_scope_from_variable, ResolvedProgram, ResolvedValue};
use crate::constraints::{
new_scope, new_scope_from_variable, new_variable_from_variables, ResolvedProgram, ResolvedValue,
};
use crate::{Expression, Function, Import, Program, Statement, Type};
use from_pest::FromPest;
@ -13,9 +15,12 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
pub(crate) fn enforce_function(
&mut self,
cs: &mut CS,
scope: String,
function: Function<F>,
arguments: Vec<Expression<F>>,
) -> ResolvedValue<F> {
let function_name = new_scope(scope.clone(), function.get_name());
// Make sure we are given the correct number of arguments
if function.parameters.len() != arguments.len() {
unimplemented!(
@ -35,11 +40,16 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
// Check that argument is correct type
match parameter.ty.clone() {
Type::U32 => {
match self.enforce_expression(cs, function.get_name(), argument) {
match self.enforce_expression(
cs,
scope.clone(),
function_name.clone(),
argument,
) {
ResolvedValue::U32(number) => {
// Store argument as variable with {function_name}_{parameter name}
let variable_name = new_scope_from_variable(
function.get_name(),
function_name.clone(),
&parameter.variable,
);
self.store(variable_name, ResolvedValue::U32(number));
@ -50,11 +60,16 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
}
}
Type::FieldElement => {
match self.enforce_expression(cs, function.get_name(), argument) {
match self.enforce_expression(
cs,
scope.clone(),
function_name.clone(),
argument,
) {
ResolvedValue::FieldElement(field) => {
// Store argument as variable with {function_name}_{parameter name}
let variable_name = new_scope_from_variable(
function.get_name(),
function_name.clone(),
&parameter.variable,
);
self.store(variable_name, ResolvedValue::FieldElement(field));
@ -63,11 +78,16 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
}
}
Type::Boolean => {
match self.enforce_expression(cs, function.get_name(), argument) {
match self.enforce_expression(
cs,
scope.clone(),
function_name.clone(),
argument,
) {
ResolvedValue::Boolean(bool) => {
// Store argument as variable with {function_name}_{parameter name}
let variable_name = new_scope_from_variable(
function.get_name(),
function_name.clone(),
&parameter.variable,
);
self.store(variable_name, ResolvedValue::Boolean(bool));
@ -90,38 +110,66 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
.clone()
.into_iter()
.for_each(|statement| match statement {
Statement::Definition(variable, expression) => {
self.enforce_definition_statement(
Statement::Return(expressions) => {
return_values = self.enforce_return_statement(
cs,
function.get_name(),
scope.clone(),
function_name.clone(),
expressions,
function.returns.to_owned(),
);
}
Statement::Assign(variable, expression) => {
self.enforce_assign_statement(
cs,
scope.clone(),
function_name.clone(),
variable,
expression,
);
}
Statement::Definition(ty, assignee, expression) => {
self.enforce_definition_statement(
cs,
scope.clone(),
function_name.clone(),
ty,
assignee,
expression,
);
}
Statement::MultipleDefinition(assignees, function_call) => {
self.enforce_multiple_definition_statement(
cs,
scope.clone(),
function_name.clone(),
assignees,
function_call,
);
}
Statement::For(index, start, stop, statements) => {
self.enforce_for_statement(
cs,
function.get_name(),
scope.clone(),
function_name.clone(),
index,
start,
stop,
statements,
);
}
Statement::Return(expressions) => {
return_values = self.enforce_return_statement(
cs,
function.get_name(),
expressions,
function.returns.to_owned(),
)
}
});
return_values
}
fn enforce_main_function(&mut self, cs: &mut CS, function: Function<F>) -> ResolvedValue<F> {
fn enforce_main_function(
&mut self,
cs: &mut CS,
scope: String,
function: Function<F>,
) -> ResolvedValue<F> {
let function_name = new_scope(scope.clone(), function.get_name());
let mut arguments = vec![];
// Iterate over main function parameters
@ -134,30 +182,33 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
// append each variable to arguments vector
arguments.push(Expression::Variable(match parameter.ty {
Type::U32 => {
self.integer_from_parameter(cs, function.get_name(), i + 1, parameter)
}
Type::FieldElement => {
self.field_element_from_parameter(cs, function.get_name(), i + 1, parameter)
self.u32_from_parameter(cs, function_name.clone(), i + 1, parameter)
}
Type::FieldElement => self.field_element_from_parameter(
cs,
function_name.clone(),
i + 1,
parameter,
),
Type::Boolean => {
self.bool_from_parameter(cs, function.get_name(), i + 1, parameter)
self.bool_from_parameter(cs, function_name.clone(), i + 1, parameter)
}
Type::Array(ref ty, _length) => match *ty.clone() {
Type::U32 => self.integer_array_from_parameter(
Type::U32 => self.u32_array_from_parameter(
cs,
function.get_name(),
function_name.clone(),
i + 1,
parameter,
),
Type::FieldElement => self.field_element_array_from_parameter(
cs,
function.get_name(),
function_name.clone(),
i + 1,
parameter,
),
Type::Boolean => self.boolean_array_from_parameter(
cs,
function.get_name(),
function_name.clone(),
i + 1,
parameter,
),
@ -167,58 +218,138 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
}))
});
self.enforce_function(cs, function, arguments)
self.enforce_function(cs, scope, function, arguments)
}
fn enforce_import(&mut self, cs: &mut CS, import: Import) {
fn enforce_import(&mut self, cs: &mut CS, scope: String, import: Import<F>) {
// Resolve program file path
let unparsed_file = fs::read_to_string(import.get_file()).expect("cannot read file");
let mut file = ast::parse(&unparsed_file).expect("unsuccessful parse");
let unparsed_file = fs::read_to_string(import.get_file())
.expect(&format!("cannot parse import {}", import.get_file()));
let mut file = ast::parse(&unparsed_file)
.expect(&format!("cannot parse import {}", import.get_file()));
// generate ast from file
let syntax_tree = ast::File::from_pest(&mut file).expect("infallible");
// generate aleo program from file
let program = Program::from(syntax_tree);
let mut program = Program::from(syntax_tree);
// recursively evaluate program statements TODO: in file scope
self.resolve_definitions(cs, program);
// Use same namespace as calling function for imported symbols
program = program.name(scope);
// store import under designated name
// self.store(name, value)
// * -> import all imports, structs, functions in the current scope
if import.is_star() {
// recursively evaluate program statements
self.resolve_definitions(cs, program);
} else {
let program_name = program.name.clone();
// match each import symbol to a symbol in the imported file
import.symbols.into_iter().for_each(|symbol| {
// see if the imported symbol is a struct
let matched_struct = program
.structs
.clone()
.into_iter()
.find(|(struct_name, _struct_def)| symbol.symbol == *struct_name);
match matched_struct {
Some((_struct_name, struct_def)) => {
// take the alias if it is present
let resolved_name = symbol.alias.unwrap_or(symbol.symbol);
let resolved_struct_name =
new_variable_from_variables(&program_name.clone(), &resolved_name);
// store imported struct under resolved name
self.store_variable(
resolved_struct_name,
ResolvedValue::StructDefinition(struct_def),
);
}
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,
);
match matched_function {
Some((_function_name, function)) => {
// take the alias if it is present
let resolved_name = symbol.alias.unwrap_or(symbol.symbol);
let resolved_function_name = new_variable_from_variables(
&program_name.clone(),
&resolved_name,
);
// store imported function under resolved name
self.store_variable(
resolved_function_name,
ResolvedValue::Function(function),
)
}
None => unimplemented!(
"cannot find imported symbol {} in imported file {}",
symbol,
program_name.clone()
),
}
}
}
});
// evaluate all import statements in imported file
program.imports.into_iter().for_each(|nested_import| {
self.enforce_import(cs, program_name.name.clone(), nested_import)
});
}
}
pub fn resolve_definitions(&mut self, cs: &mut CS, program: Program<F>) {
let program_name = program.name.clone();
// evaluate and store all imports
program
.imports
.into_iter()
.for_each(|import| self.enforce_import(cs, import));
.for_each(|import| self.enforce_import(cs, program_name.name.clone(), import));
// evaluate and store all struct definitions
program
.structs
.into_iter()
.for_each(|(variable, struct_def)| {
self.store_variable(variable, ResolvedValue::StructDefinition(struct_def));
let resolved_struct_name =
new_variable_from_variables(&program_name.clone(), &variable);
self.store_variable(
resolved_struct_name,
ResolvedValue::StructDefinition(struct_def),
);
});
// evaluate and store all function definitions
program
.functions
.into_iter()
.for_each(|(function_name, function)| {
self.store(function_name.0, ResolvedValue::Function(function));
let resolved_function_name = new_scope(program_name.name.clone(), function_name.0);
self.store(resolved_function_name, ResolvedValue::Function(function));
});
}
pub fn generate_constraints(cs: &mut CS, program: Program<F>) {
let mut resolved_program = ResolvedProgram::new();
let program_name = program.get_name();
let main_function_name = new_scope(program_name.clone(), "main".into());
resolved_program.resolve_definitions(cs, program);
let main = resolved_program
.get(&"main".into())
.get(&main_function_name)
.expect("main function not defined");
let result = match main.clone() {
ResolvedValue::Function(function) => {
resolved_program.enforce_main_function(cs, function)
resolved_program.enforce_main_function(cs, program_name, function)
}
_ => unimplemented!("main must be a function"),
};

View File

@ -1,7 +1,10 @@
//! Methods to enforce constraints on expressions in a resolved aleo program.
use crate::constraints::{new_scope_from_variable, ResolvedProgram, ResolvedValue};
use crate::{Expression, RangeOrExpression, SpreadOrExpression, StructMember, Variable};
use crate::{
new_variable_from_variable, Expression, RangeOrExpression, ResolvedStructMember,
SpreadOrExpression, StructMember, Variable,
};
use snarkos_models::curves::{Field, PrimeField};
use snarkos_models::gadgets::r1cs::ConstraintSystem;
@ -138,14 +141,15 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
fn enforce_array_expression(
&mut self,
cs: &mut CS,
scope: String,
file_scope: String,
function_scope: String,
array: Vec<Box<SpreadOrExpression<F>>>,
) -> ResolvedValue<F> {
let mut result = vec![];
array.into_iter().for_each(|element| match *element {
SpreadOrExpression::Spread(spread) => match spread {
Expression::Variable(variable) => {
let array_name = new_scope_from_variable(scope.clone(), &variable);
let array_name = new_scope_from_variable(function_scope.clone(), &variable);
match self.get(&array_name) {
Some(value) => match value {
ResolvedValue::Array(array) => result.extend(array.clone()),
@ -162,7 +166,12 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
value => unimplemented!("spreads only implemented for arrays, got {}", value),
},
SpreadOrExpression::Expression(expression) => {
result.push(self.enforce_expression(cs, scope.clone(), expression));
result.push(self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expression,
));
}
});
ResolvedValue::Array(result)
@ -171,10 +180,11 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
pub(crate) fn enforce_index(
&mut self,
cs: &mut CS,
scope: String,
file_scope: String,
function_scope: String,
index: Expression<F>,
) -> usize {
match self.enforce_expression(cs, scope.clone(), index) {
match self.enforce_expression(cs, file_scope, function_scope, index) {
ResolvedValue::U32(number) => number.value.unwrap() as usize,
value => unimplemented!("From index must resolve to an integer, got {}", value),
}
@ -183,11 +193,12 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
fn enforce_array_access_expression(
&mut self,
cs: &mut CS,
scope: String,
file_scope: String,
function_scope: String,
array: Box<Expression<F>>,
index: RangeOrExpression<F>,
) -> ResolvedValue<F> {
match self.enforce_expression(cs, scope.clone(), *array) {
match self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *array) {
ResolvedValue::Array(array) => {
match index {
RangeOrExpression::Range(from, to) => {
@ -202,7 +213,8 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
ResolvedValue::Array(array[from_resolved..to_resolved].to_owned())
}
RangeOrExpression::Expression(index) => {
let index_resolved = self.enforce_index(cs, scope.clone(), index);
let index_resolved =
self.enforce_index(cs, file_scope, function_scope, index);
array[index_resolved].to_owned()
}
}
@ -214,51 +226,62 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
fn enforce_struct_expression(
&mut self,
cs: &mut CS,
scope: String,
file_scope: String,
function_scope: String,
variable: Variable<F>,
members: Vec<StructMember<F>>,
) -> ResolvedValue<F> {
if let Some(resolved_value) = self.get_mut_variable(&variable) {
let struct_name = new_variable_from_variable(file_scope.clone(), &variable);
if let Some(resolved_value) = self.get_mut_variable(&struct_name) {
match resolved_value {
ResolvedValue::StructDefinition(struct_definition) => {
struct_definition
let resolved_members = struct_definition
.fields
.clone()
.iter()
.zip(members.clone().into_iter())
.for_each(|(field, member)| {
.map(|(field, member)| {
if field.variable != member.variable {
unimplemented!("struct field variables do not match")
}
// Resolve and possibly enforce struct fields
// do we need to store the results here?
let _result =
self.enforce_expression(cs, scope.clone(), member.expression);
});
// Resolve and enforce struct fields
let member_value = self.enforce_expression(
cs,
file_scope.clone(),
function_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"),
}
} else {
unimplemented!("Struct must be declared before it is used in an inline expression")
unimplemented!(
"Struct {} must be declared before it is used in an inline expression",
struct_name
)
}
}
fn enforce_struct_access_expression(
&mut self,
cs: &mut CS,
scope: String,
file_scope: String,
function_scope: String,
struct_variable: Box<Expression<F>>,
struct_member: Variable<F>,
) -> ResolvedValue<F> {
match self.enforce_expression(cs, scope.clone(), *struct_variable) {
match self.enforce_expression(cs, file_scope, function_scope, *struct_variable) {
ResolvedValue::StructExpression(_name, members) => {
let matched_member = members
.into_iter()
.find(|member| member.variable == struct_member);
let matched_member = members.into_iter().find(|member| member.0 == struct_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),
}
}
@ -266,29 +289,52 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
}
}
fn enforce_function_access_expression(
fn enforce_function_call_expression(
&mut self,
cs: &mut CS,
scope: String,
function: Box<Expression<F>>,
file_scope: String,
function: Variable<F>,
arguments: Vec<Expression<F>>,
) -> ResolvedValue<F> {
match self.enforce_expression(cs, scope, *function) {
ResolvedValue::Function(function) => self.enforce_function(cs, function, arguments),
value => unimplemented!("Cannot call unknown function {}", value),
let function_name = new_variable_from_variable(file_scope.clone(), &function);
match self.get_mut_variable(&function_name) {
Some(value) => match value.clone() {
ResolvedValue::Function(function) => {
// this function call is inline so we unwrap the return value
match self.enforce_function(cs, file_scope, function, arguments) {
ResolvedValue::Return(return_values) => {
if return_values.len() == 0 {
ResolvedValue::Return(vec![])
} else if return_values.len() == 1 {
return_values[0].clone()
} else {
unimplemented!("function {} returns multiple values but is used in an expression that expects one", function_name)
}
}
value => unimplemented!(
"function {} has no return value {}",
function_name,
value
),
}
}
value => unimplemented!("Cannot make function call to {}", value),
},
None => unimplemented!("Cannot call unknown function {}", function_name),
}
}
pub(crate) fn enforce_expression(
&mut self,
cs: &mut CS,
scope: String,
file_scope: String,
function_scope: String,
expression: Expression<F>,
) -> ResolvedValue<F> {
match expression {
// Variables
Expression::Variable(unresolved_variable) => {
self.enforce_variable(scope, unresolved_variable)
self.enforce_variable(function_scope, unresolved_variable)
}
// Values
@ -298,55 +344,74 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
// Binary operations
Expression::Add(left, right) => {
let resolved_left = self.enforce_expression(cs, scope.clone(), *left);
let resolved_right = self.enforce_expression(cs, scope.clone(), *right);
let resolved_left =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *left);
let resolved_right =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *right);
self.enforce_add_expression(cs, resolved_left, resolved_right)
}
Expression::Sub(left, right) => {
let resolved_left = self.enforce_expression(cs, scope.clone(), *left);
let resolved_right = self.enforce_expression(cs, scope.clone(), *right);
let resolved_left =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *left);
let resolved_right =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *right);
self.enforce_sub_expression(cs, resolved_left, resolved_right)
}
Expression::Mul(left, right) => {
let resolved_left = self.enforce_expression(cs, scope.clone(), *left);
let resolved_right = self.enforce_expression(cs, scope.clone(), *right);
let resolved_left =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *left);
let resolved_right =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *right);
self.enforce_mul_expression(cs, resolved_left, resolved_right)
}
Expression::Div(left, right) => {
let resolved_left = self.enforce_expression(cs, scope.clone(), *left);
let resolved_right = self.enforce_expression(cs, scope.clone(), *right);
let resolved_left =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *left);
let resolved_right =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *right);
self.enforce_div_expression(cs, resolved_left, resolved_right)
}
Expression::Pow(left, right) => {
let resolved_left = self.enforce_expression(cs, scope.clone(), *left);
let resolved_right = self.enforce_expression(cs, scope.clone(), *right);
let resolved_left =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *left);
let resolved_right =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *right);
self.enforce_pow_expression(cs, resolved_left, resolved_right)
}
// Boolean operations
Expression::Not(expression) => {
Self::enforce_not(self.enforce_expression(cs, scope, *expression))
}
Expression::Not(expression) => Self::enforce_not(self.enforce_expression(
cs,
file_scope,
function_scope,
*expression,
)),
Expression::Or(left, right) => {
let resolved_left = self.enforce_expression(cs, scope.clone(), *left);
let resolved_right = self.enforce_expression(cs, scope.clone(), *right);
let resolved_left =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *left);
let resolved_right =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *right);
self.enforce_or(cs, resolved_left, resolved_right)
}
Expression::And(left, right) => {
let resolved_left = self.enforce_expression(cs, scope.clone(), *left);
let resolved_right = self.enforce_expression(cs, scope.clone(), *right);
let resolved_left =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *left);
let resolved_right =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *right);
self.enforce_and(cs, resolved_left, resolved_right)
}
Expression::Eq(left, right) => {
let resolved_left = self.enforce_expression(cs, scope.clone(), *left);
let resolved_right = self.enforce_expression(cs, scope.clone(), *right);
let resolved_left =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *left);
let resolved_right =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *right);
self.enforce_eq_expression(cs, resolved_left, resolved_right)
}
@ -365,35 +430,47 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
// Conditionals
Expression::IfElse(first, second, third) => {
let resolved_first = match self.enforce_expression(cs, scope.clone(), *first) {
let resolved_first = match self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
*first,
) {
ResolvedValue::Boolean(resolved) => resolved,
_ => unimplemented!("if else conditional must resolve to boolean"),
};
if resolved_first.eq(&Boolean::Constant(true)) {
self.enforce_expression(cs, scope, *second)
self.enforce_expression(cs, file_scope, function_scope, *second)
} else {
self.enforce_expression(cs, scope, *third)
self.enforce_expression(cs, file_scope, function_scope, *third)
}
}
// Arrays
Expression::Array(array) => self.enforce_array_expression(cs, scope, array),
Expression::Array(array) => {
self.enforce_array_expression(cs, file_scope, function_scope, array)
}
Expression::ArrayAccess(array, index) => {
self.enforce_array_access_expression(cs, scope, array, *index)
self.enforce_array_access_expression(cs, file_scope, function_scope, array, *index)
}
// Structs
Expression::Struct(struct_name, members) => {
self.enforce_struct_expression(cs, scope, struct_name, members)
}
Expression::StructMemberAccess(struct_variable, struct_member) => {
self.enforce_struct_access_expression(cs, scope, struct_variable, struct_member)
self.enforce_struct_expression(cs, file_scope, function_scope, struct_name, members)
}
Expression::StructMemberAccess(struct_variable, struct_member) => self
.enforce_struct_access_expression(
cs,
file_scope,
function_scope,
struct_variable,
struct_member,
),
// Functions
Expression::FunctionCall(function, arguments) => {
self.enforce_function_access_expression(cs, scope, function, arguments)
self.enforce_function_call_expression(cs, file_scope, function, arguments)
} // _ => unimplemented!(),
}
}

View File

@ -10,7 +10,7 @@ use snarkos_models::gadgets::{
};
impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
pub(crate) fn integer_from_parameter(
pub(crate) fn u32_from_parameter(
&mut self,
cs: &mut CS,
scope: String,
@ -46,7 +46,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
parameter_variable
}
pub(crate) fn integer_array_from_parameter(
pub(crate) fn u32_array_from_parameter(
&mut self,
_cs: &mut CS,
_scope: String,

View File

@ -34,6 +34,16 @@ pub fn new_variable_from_variable<F: Field + PrimeField>(
}
}
pub fn new_variable_from_variables<F: Field + PrimeField>(
outer: &Variable<F>,
inner: &Variable<F>,
) -> Variable<F> {
Variable {
name: new_scope_from_variable(outer.name.clone(), inner),
_field: PhantomData::<F>,
}
}
impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
pub fn new() -> Self {
Self {

View File

@ -1,6 +1,6 @@
//! 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::gadgets::{utilities::boolean::Boolean, utilities::uint32::UInt32};
@ -13,18 +13,29 @@ pub enum ResolvedValue<F: Field + PrimeField> {
Boolean(Boolean),
Array(Vec<ResolvedValue<F>>),
StructDefinition(Struct<F>),
StructExpression(Variable<F>, Vec<StructMember<F>>),
StructExpression(Variable<F>, Vec<ResolvedStructMember<F>>),
Function(Function<F>),
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> {
pub(crate) fn match_type(&self, ty: &Type<F>) -> bool {
match (self, ty) {
(ResolvedValue::U32(ref _a), Type::U32) => true,
(ResolvedValue::FieldElement(ref _a), Type::FieldElement) => true,
(ResolvedValue::Boolean(ref _a), Type::Boolean) => true,
(ResolvedValue::Array(ref arr), Type::Array(ref _ty, ref len)) => arr.len() == *len, // todo: add array types
(ResolvedValue::Array(ref arr), Type::Array(ref ty, ref len)) => {
// check array lengths are equal
let mut res = arr.len() == *len;
// check each value in array matches
for value in arr {
res &= value.match_type(ty)
}
res
}
(
ResolvedValue::StructExpression(ref actual_name, ref _members),
Type::Struct(ref expected_name),
@ -60,7 +71,7 @@ impl<F: Field + PrimeField> fmt::Display for ResolvedValue<F> {
ResolvedValue::StructExpression(ref variable, ref members) => {
write!(f, "{} {{", variable)?;
for (i, member) in members.iter().enumerate() {
write!(f, "{}: {}", member.variable, member.expression)?;
write!(f, "{}: {}", member.0, member.1)?;
if i < members.len() - 1 {
write!(f, ", ")?;
}

View File

@ -17,41 +17,40 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
}
}
pub(crate) fn enforce_definition_statement(
fn store_assignment(
&mut self,
cs: &mut CS,
scope: String,
file_scope: String,
function_scope: String,
assignee: Assignee<F>,
expression: Expression<F>,
return_value: &mut ResolvedValue<F>,
) {
// Create or modify the lhs variable in the current function scope
match assignee {
Assignee::Variable(name) => {
// Store the variable in the current scope
let definition_name = new_scope_from_variable(scope.clone(), &name);
let definition_name = new_scope_from_variable(function_scope.clone(), &name);
// Evaluate the rhs expression in the current function scope
let result = self.enforce_expression(cs, scope, expression);
self.store(definition_name, result);
self.store(definition_name, return_value.to_owned());
}
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
let expected_array_name = self.resolve_assignee(scope.clone(), *array);
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, scope.clone(), 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 {
ResolvedValue::Array(old) => {
old[index] = result.to_owned();
old[index] = return_value.to_owned();
}
_ => {
unimplemented!("Cannot assign single index to array of values ")
@ -75,7 +74,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
// Modify the range of values of the array in place
match self.get_mut(&expected_array_name) {
Some(value) => match (value, result) {
Some(value) => match (value, return_value) {
(ResolvedValue::Array(old), ResolvedValue::Array(new)) => {
let to_index = to_index_option.unwrap_or(old.len());
old.splice(from_index..to_index, new.iter().cloned());
@ -94,17 +93,17 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
}
Assignee::StructMember(struct_variable, struct_member) => {
// Check that struct exists
let expected_struct_name = self.resolve_assignee(scope.clone(), *struct_variable);
let expected_struct_name =
self.resolve_assignee(function_scope.clone(), *struct_variable);
match self.get_mut(&expected_struct_name) {
Some(value) => match value {
ResolvedValue::StructExpression(_variable, members) => {
// Modify the struct member in place
let matched_member = members
.into_iter()
.find(|member| member.variable == struct_member);
let matched_member =
members.into_iter().find(|member| member.0 == struct_member);
match matched_member {
Some(mut member) => member.expression = expression,
Some(mut member) => member.1 = return_value.to_owned(),
None => unimplemented!(
"struct member {} does not exist in {}",
struct_member,
@ -122,13 +121,88 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
}
}
}
};
}
}
pub(crate) fn enforce_assign_statement(
&mut self,
cs: &mut CS,
file_scope: String,
function_scope: String,
assignee: Assignee<F>,
expression: Expression<F>,
) {
let result_value = &mut self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expression,
);
self.store_assignment(cs, file_scope, function_scope, assignee, result_value);
}
pub(crate) fn enforce_definition_statement(
&mut self,
cs: &mut CS,
file_scope: String,
function_scope: String,
ty: Type<F>,
assignee: Assignee<F>,
expression: Expression<F>,
) {
let result_value = &mut self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expression,
);
if result_value.match_type(&ty) {
self.store_assignment(cs, file_scope, function_scope, assignee, result_value);
} else {
unimplemented!("incompatible types {} = {}", assignee, result_value)
}
}
pub(crate) fn enforce_multiple_definition_statement(
&mut self,
cs: &mut CS,
file_scope: String,
function_scope: String,
assignees: Vec<Assignee<F>>,
function: Expression<F>,
) {
// Expect return values from function
let return_values =
match self.enforce_expression(cs, file_scope.clone(), function_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.store_assignment(
cs,
file_scope.clone(),
function_scope.clone(),
assignee,
&mut return_value,
);
});
}
pub(crate) fn enforce_return_statement(
&mut self,
cs: &mut CS,
scope: String,
file_scope: String,
function_scope: String,
statements: Vec<Expression<F>>,
return_types: Vec<Type<F>>,
) -> ResolvedValue<F> {
@ -137,7 +211,12 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
.into_iter()
.zip(return_types.into_iter())
.map(|(expression, ty)| {
let result = self.enforce_expression(cs, scope.clone(), expression);
let result = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expression,
);
if !result.match_type(&ty) {
unimplemented!("expected return type {}, got {}", ty, result)
} else {
@ -151,20 +230,54 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
fn enforce_statement(
&mut self,
cs: &mut CS,
scope: String,
file_scope: String,
function_scope: String,
statement: Statement<F>,
return_types: Vec<Type<F>>,
) {
match statement {
Statement::Definition(variable, expression) => {
self.enforce_definition_statement(cs, scope, variable, expression);
}
Statement::For(index, start, stop, statements) => {
self.enforce_for_statement(cs, scope, index, start, stop, statements);
}
Statement::Return(statements) => {
// TODO: add support for early termination
let _res = self.enforce_return_statement(cs, scope, statements, return_types);
let _res = self.enforce_return_statement(
cs,
file_scope,
function_scope,
statements,
return_types,
);
}
Statement::Assign(variable, expression) => {
self.enforce_assign_statement(cs, file_scope, function_scope, variable, expression);
}
Statement::Definition(ty, assignee, expression) => {
self.enforce_definition_statement(
cs,
file_scope,
function_scope,
ty,
assignee,
expression,
);
}
Statement::MultipleDefinition(assignees, function) => {
self.enforce_multiple_definition_statement(
cs,
file_scope,
function_scope,
assignees,
function,
);
}
Statement::For(index, start, stop, statements) => {
self.enforce_for_statement(
cs,
file_scope,
function_scope,
index,
start,
stop,
statements,
);
}
};
}
@ -172,7 +285,8 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
pub(crate) fn enforce_for_statement(
&mut self,
cs: &mut CS,
scope: String,
file_scope: String,
function_scope: String,
index: Variable<F>,
start: Integer,
stop: Integer,
@ -181,14 +295,19 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
for i in start.to_usize()..stop.to_usize() {
// Store index in current function scope.
// For loop scope is not implemented.
let index_name = new_scope_from_variable(scope.clone(), &index);
let index_name = new_scope_from_variable(function_scope.clone(), &index);
self.store(index_name, ResolvedValue::U32(UInt32::constant(i as u32)));
// Evaluate statements (for loop statements should not have a return type)
statements
.clone()
.into_iter()
.for_each(|statement| self.enforce_statement(cs, scope.clone(), statement, vec![]));
statements.clone().into_iter().for_each(|statement| {
self.enforce_statement(
cs,
file_scope.clone(),
function_scope.clone(),
statement,
vec![],
)
});
}
}
}

View File

@ -1,44 +1,27 @@
use crate::Variable;
use snarkos_models::curves::{Field, PrimeField};
use std::fmt;
use std::path::Path;
type ImportPath<'ast> = &'ast Path;
pub(crate) type PathString<'ast> = &'ast str;
// pub(crate) type Variable<'ast = &'ast str;
#[derive(Clone)]
pub struct Import<'ast> {
source: ImportPath<'ast>,
symbol: Option<PathString<'ast>>,
alias: Option<PathString<'ast>>,
pub struct ImportSymbol<F: Field + PrimeField> {
pub symbol: Variable<F>,
pub alias: Option<Variable<F>>,
}
impl<'ast> Import<'ast> {
pub fn new(symbol: Option<PathString<'ast>>, source: ImportPath<'ast>) -> Import<'ast> {
Import {
source,
symbol,
alias: None,
}
}
#[derive(Clone)]
pub struct Import<'ast, F: Field + PrimeField> {
pub(crate) source: ImportPath<'ast>,
pub(crate) symbols: Vec<ImportSymbol<F>>,
}
pub fn new_with_alias(
symbol: Option<PathString<'ast>>,
source: ImportPath<'ast>,
alias: PathString<'ast>,
) -> Import<'ast> {
Import {
source,
symbol,
alias: Some(alias),
}
}
pub fn alias(mut self, alias: Option<PathString<'ast>>) -> Self {
self.alias = alias;
self
}
pub fn get_alias(&self) -> &Option<PathString<'ast>> {
&self.alias
impl<'ast, F: Field + PrimeField> Import<'ast, F> {
pub fn new(source: ImportPath<'ast>, symbols: Vec<ImportSymbol<F>>) -> Import<'ast, F> {
Import { source, symbols }
}
pub fn get_source(&self) -> &Path {
@ -49,27 +32,54 @@ impl<'ast> Import<'ast> {
let path = self.get_source().to_str().unwrap();
format!("{}.leo", path)
}
pub fn is_star(&self) -> bool {
self.symbols.is_empty()
}
}
impl<'ast> fmt::Display for Import<'ast> {
impl<F: Field + PrimeField> fmt::Display for ImportSymbol<F> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.alias {
Some(ref alias) => write!(f, "import {} as {}", self.source.display(), alias),
None => write!(f, "import {}", self.source.display()),
if self.alias.is_some() {
write!(f, "\t{} as {}", self.symbol, self.alias.as_ref().unwrap())
} else {
write!(f, "\t{}", self.symbol)
}
}
}
impl<'ast> fmt::Debug for Import<'ast> {
impl<'ast, F: Field + PrimeField> fmt::Display for Import<'ast, F> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.alias {
Some(ref alias) => write!(
f,
"import(source: {}, alias: {})",
self.source.display(),
alias
),
None => write!(f, "import( source: {})", self.source.display()),
write!(f, "from {} import ", self.source.display())?;
if self.symbols.is_empty() {
write!(f, "*")
} else {
write!(f, "{{\n")?;
for (i, symbol) in self.symbols.iter().enumerate() {
write!(f, "{}", symbol)?;
if i < self.symbols.len() - 1 {
write!(f, ",\n")?;
}
}
write!(f, "\n}}")
}
}
}
impl<'ast, F: Field + PrimeField> fmt::Debug for Import<'ast, F> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "from {} import ", self.source.display())?;
if self.symbols.is_empty() {
write!(f, "*")
} else {
write!(f, "{{\n")?;
for (i, symbol) in self.symbols.iter().enumerate() {
write!(f, "{}", symbol)?;
if i < self.symbols.len() - 1 {
write!(f, ",\n")?;
}
}
write!(f, "\n}}")
}
}
}

View File

@ -76,6 +76,10 @@ protected_name = { visibility | value_boolean | "return" }
// "def" | "in" | "return" | "struct" | "true" }
variable = @{ ((!protected_name ~ ASCII_ALPHA) | (protected_name ~ (ASCII_ALPHANUMERIC | "_"))) ~ (ASCII_ALPHANUMERIC | "_")* }
optionally_typed_variable = { (ty ~ variable) | (variable)}
optionally_typed_variable_tuple = _{ optionally_typed_variable ~ ("," ~ optionally_typed_variable)* }
expression_primitive = { value | variable }
/// Access
@ -139,17 +143,19 @@ expression_tuple = _{ (expression ~ ("," ~ expression)*)? }
/// Statements
statement_assign = { assignee ~ "=" ~ expression }
statement_definition = { ty ~ variable ~ "=" ~ expression }
statement_return = { "return" ~ expression_tuple }
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_return
| (statement_for
| statement_multiple_assignment
| statement_definition
| statement_assign
) ~ NEWLINE
) ~ LINE_END
) ~ NEWLINE*
}
@ -159,19 +165,23 @@ parameter = {variable ~ ":" ~ visibility? ~ ty}
parameter_list = _{(parameter ~ ("," ~ parameter)*)?}
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
COMMENT = _{ ("/*" ~ (!"*/" ~ ANY)* ~ "*/") | ("//" ~ (!NEWLINE ~ ANY)*) }
WHITESPACE = _{ " " | "\t" ~ (NEWLINE)* }
LINE_END = _{";" ~ NEWLINE*}
/// Imports
import = { main_import | from_import }
from_import = { "from" ~ "\"" ~ import_source ~ "\"" ~ "import" ~ variable ~ ("as" ~ variable)? ~ NEWLINE*}
main_import = {"import" ~ "\"" ~ import_source ~ "\"" ~ ("as" ~ variable)? ~ NEWLINE+}
import_source = @{(!"\"" ~ ANY)*}
import_symbol = { variable ~ ("as" ~ variable)? }
import_symbol_tuple = _{ import_symbol ~ ("," ~ NEWLINE* ~ import_symbol)* }
import = { "from" ~ "\"" ~ import_source ~ "\"" ~ "import" ~ ("*" | ("{" ~ NEWLINE* ~ import_symbol_tuple ~ NEWLINE* ~ "}")) ~ LINE_END}
// import = { main_import | from_import }
// main_import = {"import" ~ "\"" ~ import_source ~ "\"" ~ ("as" ~ variable)? ~ NEWLINE+}
/// Program File

View File

@ -1,10 +1,12 @@
//! Module containing structs and types that make up an Leo program.
extern crate from_pest;
#[macro_use] extern crate lazy_static;
#[macro_use]
extern crate lazy_static;
extern crate pest;
extern crate pest_ast;
#[macro_use] extern crate pest_derive;
#[macro_use]
extern crate pest_derive;
pub mod ast;

View File

@ -86,7 +86,7 @@ pub enum Expression<F: Field + PrimeField> {
StructMemberAccess(Box<Expression<F>>, Variable<F>), // (struct name, struct member name)
// Functions
FunctionCall(Box<Expression<F>>, Vec<Expression<F>>),
FunctionCall(Variable<F>, Vec<Expression<F>>),
}
/// Definition assignee: v, arr[0..2], Point p.x
@ -97,16 +97,7 @@ pub enum Assignee<F: Field + PrimeField> {
StructMember(Box<Assignee<F>>, Variable<F>),
}
/// Program statement that defines some action (or expression) to be carried out.
#[derive(Clone)]
pub enum Statement<F: Field + PrimeField> {
// Declaration(Variable),
Definition(Assignee<F>, Expression<F>),
For(Variable<F>, Integer, Integer, Vec<Statement<F>>),
Return(Vec<Expression<F>>),
}
/// Explicit type used for defining struct members and function parameters
/// Explicit type used for defining a variable or expression type
#[derive(Clone, Debug, PartialEq)]
pub enum Type<F: Field + PrimeField> {
U32,
@ -116,6 +107,17 @@ pub enum Type<F: Field + PrimeField> {
Struct(Variable<F>),
}
/// Program statement that defines some action (or expression) to be carried out.
#[derive(Clone)]
pub enum Statement<F: Field + PrimeField> {
// Declaration(Variable),
Return(Vec<Expression<F>>),
Assign(Assignee<F>, Expression<F>),
Definition(Type<F>, Assignee<F>, Expression<F>),
MultipleDefinition(Vec<Assignee<F>>, Expression<F>),
For(Variable<F>, Integer, Integer, Vec<Statement<F>>),
}
#[derive(Clone, Debug)]
pub struct StructMember<F: Field + PrimeField> {
pub variable: Variable<F>,
@ -165,12 +167,16 @@ impl<F: Field + PrimeField> Function<F> {
#[derive(Debug, Clone)]
pub struct Program<'ast, F: Field + PrimeField> {
pub name: Variable<F>,
pub imports: Vec<Import<'ast>>,
pub imports: Vec<Import<'ast, F>>,
pub structs: HashMap<Variable<F>, Struct<F>>,
pub functions: HashMap<FunctionName, Function<F>>,
}
impl<'ast, F: Field + PrimeField> Program<'ast, F> {
pub fn get_name(&self) -> String {
self.name.name.clone()
}
pub fn name(mut self, name: String) -> Self {
self.name = Variable {
name,

View File

@ -141,21 +141,37 @@ impl<F: Field + PrimeField> fmt::Display for Assignee<F> {
impl<F: Field + PrimeField> fmt::Display for Statement<F> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Statement::Definition(ref variable, ref statement) => {
write!(f, "{} = {}", variable, statement)
Statement::Return(ref statements) => {
write!(f, "return ")?;
for (i, value) in statements.iter().enumerate() {
write!(f, "{}", value)?;
if i < statements.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, "\n")
}
Statement::Assign(ref variable, ref statement) => {
write!(f, "{} = {};", variable, statement)
}
Statement::Definition(ref ty, ref assignee, ref statement) => {
write!(f, "{} {} = {};", ty, assignee, statement)
}
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) => {
write!(f, "for {} in {}..{} do\n", var, start, stop)?;
for l in list {
write!(f, "\t\t{}\n", l)?;
}
write!(f, "\tendfor")
}
Statement::Return(ref statements) => {
statements.iter().for_each(|statement| {
write!(f, "return {}", statement).unwrap();
});
write!(f, "\n")
write!(f, "\tendfor;")
}
}
}
@ -164,21 +180,37 @@ impl<F: Field + PrimeField> fmt::Display for Statement<F> {
impl<F: Field + PrimeField> fmt::Debug for Statement<F> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Statement::Definition(ref variable, ref statement) => {
write!(f, "{} = {}", variable, statement)
Statement::Return(ref statements) => {
write!(f, "return ")?;
for (i, value) in statements.iter().enumerate() {
write!(f, "{}", value)?;
if i < statements.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, "\n")
}
Statement::Assign(ref variable, ref statement) => {
write!(f, "{} = {};", variable, statement)
}
Statement::Definition(ref ty, ref assignee, ref statement) => {
write!(f, "{} {} = {};", ty, assignee, statement)
}
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) => {
write!(f, "for {:?} in {:?}..{:?} do\n", var, start, stop)?;
for l in list {
write!(f, "\t\t{:?}\n", l)?;
}
write!(f, "\tendfor")
}
Statement::Return(ref statements) => {
statements.iter().for_each(|statement| {
write!(f, "return {}", statement).unwrap();
});
write!(f, "\n")
write!(f, "\tendfor;")
}
}
}

View File

@ -1,7 +1,7 @@
//! Logic to convert from an abstract syntax tree (ast) representation to a typed aleo program.
use crate::ast;
use crate::{types, Import, PathString};
use crate::{types, Import, ImportSymbol};
use snarkos_models::curves::{Field, PrimeField};
use std::collections::HashMap;
@ -192,43 +192,6 @@ impl<'ast, F: Field + PrimeField> From<ast::TernaryExpression<'ast>> for types::
}
}
impl<'ast, F: Field + PrimeField> From<ast::PostfixExpression<'ast>> for types::Expression<F> {
fn from(expression: ast::PostfixExpression<'ast>) -> Self {
let variable = types::Expression::Variable(types::Variable::from(expression.variable));
// 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
// we start with the id, and we fold the array of accesses by wrapping the current value
expression
.accesses
.into_iter()
.fold(variable, |acc, access| match access {
ast::Access::Call(function) => match acc {
types::Expression::Variable(_) => types::Expression::FunctionCall(
Box::new(acc),
function
.expressions
.into_iter()
.map(|expression| types::Expression::from(expression))
.collect(),
),
expression => {
unimplemented!("only function names are callable, found \"{}\"", expression)
}
},
ast::Access::Member(struct_member) => types::Expression::StructMemberAccess(
Box::new(acc),
types::Variable::from(struct_member.variable),
),
ast::Access::Array(array) => types::Expression::ArrayAccess(
Box::new(acc),
Box::new(types::RangeOrExpression::from(array.expression)),
),
})
}
}
impl<'ast, F: Field + PrimeField> From<ast::ArrayInlineExpression<'ast>> for types::Expression<F> {
fn from(array: ast::ArrayInlineExpression<'ast>) -> Self {
types::Expression::Array(
@ -251,6 +214,65 @@ impl<'ast, F: Field + PrimeField> From<ast::ArrayInitializerExpression<'ast>>
}
}
impl<'ast, F: Field + PrimeField> From<ast::InlineStructMember<'ast>> for types::StructMember<F> {
fn from(member: ast::InlineStructMember<'ast>) -> Self {
types::StructMember {
variable: types::Variable::from(member.variable),
expression: types::Expression::from(member.expression),
}
}
}
impl<'ast, F: Field + PrimeField> From<ast::StructInlineExpression<'ast>> for types::Expression<F> {
fn from(expression: ast::StructInlineExpression<'ast>) -> Self {
let variable = types::Variable::from(expression.variable);
let members = expression
.members
.into_iter()
.map(|member| types::StructMember::from(member))
.collect::<Vec<types::StructMember<F>>>();
types::Expression::Struct(variable, members)
}
}
impl<'ast, F: Field + PrimeField> From<ast::PostfixExpression<'ast>> for types::Expression<F> {
fn from(expression: ast::PostfixExpression<'ast>) -> Self {
let variable = types::Expression::Variable(types::Variable::from(expression.variable));
// 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
// we start with the id, and we fold the array of accesses by wrapping the current value
expression
.accesses
.into_iter()
.fold(variable, |acc, access| match access {
ast::Access::Call(function) => match acc {
types::Expression::Variable(variable) => types::Expression::FunctionCall(
variable,
function
.expressions
.into_iter()
.map(|expression| types::Expression::from(expression))
.collect(),
),
expression => {
unimplemented!("only function names are callable, found \"{}\"", expression)
}
},
ast::Access::Member(struct_member) => types::Expression::StructMemberAccess(
Box::new(acc),
types::Variable::from(struct_member.variable),
),
ast::Access::Array(array) => types::Expression::ArrayAccess(
Box::new(acc),
Box::new(types::RangeOrExpression::from(array.expression)),
),
})
}
}
impl<'ast, F: Field + PrimeField> From<ast::Expression<'ast>> for types::Expression<F> {
fn from(expression: ast::Expression<'ast>) -> Self {
match expression {
@ -261,18 +283,13 @@ impl<'ast, F: Field + PrimeField> From<ast::Expression<'ast>> for types::Express
ast::Expression::Ternary(expression) => types::Expression::from(expression),
ast::Expression::ArrayInline(expression) => types::Expression::from(expression),
ast::Expression::ArrayInitializer(expression) => types::Expression::from(expression),
ast::Expression::StructInline(_expression) => {
unimplemented!("unknown type for inline struct expression")
}
ast::Expression::StructInline(expression) => types::Expression::from(expression),
ast::Expression::Postfix(expression) => types::Expression::from(expression),
// _ => unimplemented!(),
}
}
}
/// pest ast -> typed types::Expression
/// For defined types (ex: u32[4]) we manually construct the expression instead of implementing the From trait.
/// This saves us from having to resolve things at a later point in time.
impl<'ast, F: Field + PrimeField> types::Expression<F> {
fn get_count(count: ast::Value<'ast>) -> usize {
match count {
@ -284,34 +301,6 @@ impl<'ast, F: Field + PrimeField> types::Expression<F> {
size => unimplemented!("Array size should be an integer {}", size),
}
}
fn from_struct(ty: ast::StructType<'ast>, expression: ast::Expression<'ast>) -> Self {
let declaration_struct = ty.variable.value;
match expression {
ast::Expression::StructInline(inline_struct) => {
if inline_struct.variable.value != declaration_struct {
unimplemented!("Declared struct type must match inline struct type")
}
let variable = types::Variable::from(inline_struct.variable);
let members = inline_struct
.members
.into_iter()
.map(|member| types::StructMember::from(member))
.collect::<Vec<types::StructMember<F>>>();
types::Expression::Struct(variable, members)
}
_ => unimplemented!("Struct declaration must be followed by inline struct"),
}
}
fn from_type(ty: ast::Type<'ast>, expression: ast::Expression<'ast>) -> Self {
match ty {
ast::Type::Basic(_ty) => Self::from(expression),
ast::Type::Array(_ty) => Self::from(expression),
ast::Type::Struct(ty) => Self::from_struct(ty, expression),
}
}
}
/// pest ast -> types::Assignee
@ -345,24 +334,6 @@ impl<'ast, F: Field + PrimeField> From<ast::Assignee<'ast>> for types::Assignee<
/// 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> {
fn from(statement: ast::ReturnStatement<'ast>) -> Self {
types::Statement::Return(
@ -399,13 +370,57 @@ 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::Assign(
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::Type::from(statement.ty),
types::Assignee::from(statement.variable),
types::Expression::from(statement.expression),
)
}
}
impl<'ast, F: Field + PrimeField> From<ast::Statement<'ast>> for types::Statement<F> {
fn from(statement: ast::Statement<'ast>) -> Self {
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::Definition(statement) => types::Statement::from(statement),
ast::Statement::Iteration(statement) => types::Statement::from(statement),
ast::Statement::Return(statement) => types::Statement::from(statement),
}
}
}
@ -449,15 +464,6 @@ impl<'ast, F: Field + PrimeField> From<ast::Type<'ast>> for types::Type<F> {
/// pest ast -> types::Struct
impl<'ast, F: Field + PrimeField> From<ast::InlineStructMember<'ast>> for types::StructMember<F> {
fn from(member: ast::InlineStructMember<'ast>) -> Self {
types::StructMember {
variable: types::Variable::from(member.variable),
expression: types::Expression::from(member.expression),
}
}
}
impl<'ast, F: Field + PrimeField> From<ast::StructField<'ast>> for types::StructField<F> {
fn from(struct_field: ast::StructField<'ast>) -> Self {
types::StructField {
@ -485,7 +491,6 @@ impl<'ast, F: Field + PrimeField> From<ast::Struct<'ast>> for types::Struct<F> {
impl<'ast, F: Field + PrimeField> From<ast::Parameter<'ast>> for types::Parameter<F> {
fn from(parameter: ast::Parameter<'ast>) -> Self {
let ty = types::Type::from(parameter.ty);
println!("type {}", ty);
let variable = types::Variable::from(parameter.variable);
if parameter.visibility.is_some() {
@ -546,22 +551,24 @@ impl<'ast, F: Field + PrimeField> From<ast::Function<'ast>> for types::Function<
/// pest ast -> Import
impl<'ast> From<ast::Variable<'ast>> for PathString<'ast> {
fn from(import: ast::Variable<'ast>) -> Self {
import.span.as_str()
impl<'ast, F: Field + PrimeField> From<ast::ImportSymbol<'ast>> for ImportSymbol<F> {
fn from(symbol: ast::ImportSymbol<'ast>) -> Self {
ImportSymbol {
symbol: types::Variable::from(symbol.value),
alias: symbol.alias.map(|alias| types::Variable::from(alias)),
}
}
}
impl<'ast> From<ast::Import<'ast>> for Import<'ast> {
impl<'ast, F: Field + PrimeField> From<ast::Import<'ast>> for Import<'ast, F> {
fn from(import: ast::Import<'ast>) -> Self {
match import {
ast::Import::Main(import) => Import::new(None, Path::new(import.source.span.as_str()))
.alias(import.alias.map(|alias| PathString::from(alias))),
ast::Import::From(import) => Import::new(
Some(PathString::from(import.symbol)),
Path::new(import.source.span.as_str()),
)
.alias(import.alias.map(|alias| PathString::from(alias))),
Import {
source: Path::new(import.source.span.as_str()),
symbols: import
.symbols
.into_iter()
.map(|symbol| ImportSymbol::from(symbol))
.collect(),
}
}
}
@ -575,7 +582,7 @@ impl<'ast, F: Field + PrimeField> From<ast::File<'ast>> for types::Program<'ast,
.imports
.into_iter()
.map(|import| Import::from(import))
.collect::<Vec<Import>>();
.collect::<Vec<Import<'ast, F>>>();
let mut structs = HashMap::new();
let mut functions = HashMap::new();