const func arguments

This commit is contained in:
Protryon 2021-02-04 07:35:12 -08:00
parent 90fc6a9c12
commit 9c6eb23a1e
18 changed files with 142 additions and 65 deletions

View File

@ -29,7 +29,7 @@ use crate::{
Span,
Type,
};
pub use leo_ast::BinaryOperation;
pub use leo_ast::{BinaryOperation, Node as AstNode};
use std::{
cell::RefCell,
@ -194,25 +194,33 @@ impl FromAst<leo_ast::CallExpression> for CallExpression {
));
}
}
if value.arguments.len() != function.argument_types.len() {
if value.arguments.len() != function.arguments.len() {
return Err(AsgConvertError::unexpected_call_argument_count(
function.argument_types.len(),
function.arguments.len(),
value.arguments.len(),
&value.span,
));
}
let arguments = value
.arguments
.iter()
.zip(function.arguments.iter())
.map(|(expr, argument)| {
let argument = argument.borrow();
let converted =
Arc::<Expression>::from_ast(scope, expr, Some(argument.type_.clone().strong().partial()))?;
if argument.const_ && !converted.is_consty() {
return Err(AsgConvertError::unexpected_nonconst(&expr.span()));
}
Ok(converted)
})
.collect::<Result<Vec<_>, AsgConvertError>>()?;
Ok(CallExpression {
parent: RefCell::new(None),
span: Some(value.span.clone()),
arguments: value
.arguments
.iter()
.zip(function.argument_types.iter())
.map(|(expr, argument)| {
Arc::<Expression>::from_ast(scope, expr, Some(argument.clone().strong().partial()))
})
.collect::<Result<Vec<_>, AsgConvertError>>()?,
arguments,
function,
target,
})

View File

@ -29,7 +29,6 @@ use crate::{
Statement,
Type,
Variable,
VariableDeclaration,
};
use std::{
@ -61,7 +60,7 @@ impl ExpressionNode for VariableRef {
fn enforce_parents(&self, _expr: &Arc<Expression>) {}
fn get_type(&self) -> Option<Type> {
Some(self.variable.borrow().type_.clone())
Some(self.variable.borrow().type_.clone().strong().clone())
}
fn is_mut_ref(&self) -> bool {
@ -103,7 +102,7 @@ impl ExpressionNode for VariableRef {
fn is_consty(&self) -> bool {
let variable = self.variable.borrow();
if variable.declaration == VariableDeclaration::IterationDefinition {
if variable.const_ {
return true;
}
if variable.mutable || variable.assignments.len() != 1 {

View File

@ -127,8 +127,9 @@ impl Input {
container: Arc::new(RefCell::new(crate::InnerVariable {
id: uuid::Uuid::new_v4(),
name: Identifier::new("input".to_string()),
type_: Type::Circuit(container_circuit),
type_: Type::Circuit(container_circuit).weak(),
mutable: false,
const_: false,
declaration: crate::VariableDeclaration::Input,
references: vec![],
assignments: vec![],

View File

@ -50,7 +50,7 @@ pub struct Function {
pub name: RefCell<Identifier>,
pub output: WeakType,
pub has_input: bool,
pub argument_types: Vec<WeakType>,
pub arguments: Vec<Variable>,
pub circuit: RefCell<Option<Weak<Circuit>>>,
pub body: RefCell<Weak<FunctionBody>>,
pub qualifier: FunctionQualifier,
@ -69,7 +69,6 @@ impl Eq for Function {}
pub struct FunctionBody {
pub span: Option<Span>,
pub function: Arc<Function>,
pub arguments: Vec<Variable>,
pub body: Arc<Statement>,
pub scope: Scope,
}
@ -92,7 +91,7 @@ impl Function {
let mut qualifier = FunctionQualifier::Static;
let mut has_input = false;
let mut argument_types = vec![];
let mut arguments = vec![];
{
for input in value.input.iter() {
match input {
@ -105,8 +104,24 @@ impl Function {
FunctionInput::MutSelfKeyword(_) => {
qualifier = FunctionQualifier::MutSelfRef;
}
FunctionInput::Variable(leo_ast::FunctionInputVariable { type_, .. }) => {
argument_types.push(scope.borrow().resolve_ast_type(&type_)?.into());
FunctionInput::Variable(leo_ast::FunctionInputVariable {
identifier,
mutable,
const_,
type_,
span: _span,
}) => {
let variable = Arc::new(RefCell::new(crate::InnerVariable {
id: Uuid::new_v4(),
name: identifier.clone(),
type_: scope.borrow().resolve_ast_type(&type_)?.weak(),
mutable: *mutable,
const_: *const_,
declaration: crate::VariableDeclaration::Parameter,
references: vec![],
assignments: vec![],
}));
arguments.push(variable.clone());
}
}
}
@ -119,7 +134,7 @@ impl Function {
name: RefCell::new(value.identifier.clone()),
output: output.into(),
has_input,
argument_types,
arguments,
circuit: RefCell::new(None),
body: RefCell::new(Weak::new()),
qualifier,
@ -134,7 +149,6 @@ impl FunctionBody {
function: Arc<Function>,
) -> Result<FunctionBody, AsgConvertError> {
let new_scope = InnerScope::make_subscope(scope);
let mut arguments = vec![];
{
let mut scope_borrow = new_scope.borrow_mut();
if function.qualifier != FunctionQualifier::Static {
@ -142,8 +156,9 @@ impl FunctionBody {
let self_variable = Arc::new(RefCell::new(crate::InnerVariable {
id: Uuid::new_v4(),
name: Identifier::new("self".to_string()),
type_: Type::Circuit(circuit.as_ref().unwrap().upgrade().unwrap()),
type_: WeakType::Circuit(circuit.as_ref().unwrap().clone()),
mutable: function.qualifier == FunctionQualifier::MutSelfRef,
const_: false,
declaration: crate::VariableDeclaration::Parameter,
references: vec![],
assignments: vec![],
@ -151,30 +166,9 @@ impl FunctionBody {
scope_borrow.variables.insert("self".to_string(), self_variable);
}
scope_borrow.function = Some(function.clone());
for input in value.input.iter() {
match input {
FunctionInput::InputKeyword(_) => {}
FunctionInput::SelfKeyword(_) => {}
FunctionInput::MutSelfKeyword(_) => {}
FunctionInput::Variable(leo_ast::FunctionInputVariable {
identifier,
mutable,
type_,
span: _span,
}) => {
let variable = Arc::new(RefCell::new(crate::InnerVariable {
id: Uuid::new_v4(),
name: identifier.clone(),
type_: scope_borrow.resolve_ast_type(&type_)?,
mutable: *mutable,
declaration: crate::VariableDeclaration::Parameter,
references: vec![],
assignments: vec![],
}));
arguments.push(variable.clone());
scope_borrow.variables.insert(identifier.name.clone(), variable);
}
}
for argument in function.arguments.iter() {
let name = argument.borrow().name.name.clone();
scope_borrow.variables.insert(name, argument.clone());
}
}
let main_block = BlockStatement::from_ast(&new_scope, &value.block, None)?;
@ -198,7 +192,6 @@ impl FunctionBody {
Ok(FunctionBody {
span: Some(value.span.clone()),
function,
arguments,
body: Arc::new(Statement::Block(main_block)),
scope: new_scope,
})
@ -209,14 +202,16 @@ impl Into<leo_ast::Function> for &Function {
fn into(self) -> leo_ast::Function {
let (input, body, span) = match self.body.borrow().upgrade() {
Some(body) => (
body.arguments
body.function
.arguments
.iter()
.map(|variable| {
let variable = variable.borrow();
leo_ast::FunctionInput::Variable(leo_ast::FunctionInputVariable {
identifier: variable.name.clone(),
mutable: variable.mutable,
type_: (&variable.type_).into(),
const_: variable.const_,
type_: (&variable.type_.clone().strong()).into(),
span: Span::default(),
})
})

View File

@ -92,7 +92,7 @@ impl FromAst<leo_ast::AssignStatement> for Arc<Statement> {
if !variable.borrow().mutable {
return Err(AsgConvertError::immutable_assignment(&name, &statement.span));
}
let mut target_type: Option<PartialType> = Some(variable.borrow().type_.clone().into());
let mut target_type: Option<PartialType> = Some(variable.borrow().type_.clone().strong().into());
let mut target_accesses = vec![];
for access in statement.assignee.accesses.iter() {

View File

@ -98,8 +98,10 @@ impl FromAst<leo_ast::DefinitionStatement> for Arc<Statement> {
id: uuid::Uuid::new_v4(),
name: variable.identifier.clone(),
type_: type_
.ok_or_else(|| AsgConvertError::unresolved_type(&variable.identifier.name, &statement.span))?,
.ok_or_else(|| AsgConvertError::unresolved_type(&variable.identifier.name, &statement.span))?
.weak(),
mutable: variable.mutable,
const_: false,
declaration: crate::VariableDeclaration::Definition,
references: vec![],
assignments: vec![],
@ -144,7 +146,7 @@ impl Into<leo_ast::DefinitionStatement> for &DefinitionStatement {
span: variable.name.span.clone(),
});
if type_.is_none() {
type_ = Some((&variable.type_).into());
type_ = Some((&variable.type_.clone().strong()).into());
}
}

View File

@ -64,8 +64,10 @@ impl FromAst<leo_ast::IterationStatement> for Arc<Statement> {
name: statement.variable.clone(),
type_: start
.get_type()
.ok_or_else(|| AsgConvertError::unresolved_type(&statement.variable.name, &statement.span))?,
.ok_or_else(|| AsgConvertError::unresolved_type(&statement.variable.name, &statement.span))?
.weak(),
mutable: false,
const_: true,
declaration: crate::VariableDeclaration::IterationDefinition,
references: vec![],
assignments: vec![],

View File

@ -157,6 +157,10 @@ impl Type {
self.into()
}
pub fn weak(self) -> WeakType {
self.into()
}
pub fn is_unit(&self) -> bool {
matches!(self, Type::Tuple(t) if t.is_empty())
}

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{Expression, Statement, Type};
use crate::{Expression, Statement, WeakType};
use leo_ast::Identifier;
use std::{
@ -36,8 +36,9 @@ pub enum VariableDeclaration {
pub struct InnerVariable {
pub id: Uuid,
pub name: Identifier,
pub type_: Type,
pub type_: WeakType,
pub mutable: bool,
pub const_: bool, // only function arguments, const var definitions NOT included
pub declaration: VariableDeclaration,
pub references: Vec<Weak<Expression>>, // all Expression::VariableRef or panic
pub assignments: Vec<Weak<Statement>>, // all Statement::Assign or panic -- must be 1 if not mutable, or 0 if declaration == input | parameter

View File

@ -44,6 +44,66 @@ fn test_iteration() {
load_asg(program_string).unwrap();
}
#[test]
fn test_const_args() {
let program_string = r#"
function one(const value: u32) -> u32 {
return value + 1
}
function main() {
let mut a = 0u32;
for i in 0..10 {
a += one(i);
}
console.assert(a == 20u32);
}
"#;
load_asg(program_string).unwrap();
}
#[test]
fn test_const_args_used() {
let program_string = r#"
function index(arr: [u8; 3], const value: u32) -> u8 {
return arr[value]
}
function main() {
let mut a = 0u8;
let arr = [1u8, 2, 3];
for i in 0..3 {
a += index(arr, i);
}
console.assert(a == 6u8);
}
"#;
load_asg(program_string).unwrap();
}
#[test]
fn test_const_args_fail() {
let program_string = r#"
function index(arr: [u8; 3], const value: u32) -> u8 {
return arr[value]
}
function main(x_value: u32) {
let mut a = 0u8;
let arr = [1u8, 2, 3];
a += index(arr, x_value);
console.assert(a == 1u8);
}
"#;
load_asg(program_string).err().unwrap();
}
#[test]
fn test_iteration_repeated() {
let program_string = include_str!("iteration_repeated.leo");

View File

@ -81,7 +81,6 @@ fn test_function_input_mut() {
}
#[test]
#[ignore]
fn test_swap() {
let program_string = include_str!("swap.leo");
load_asg(program_string).unwrap();

View File

@ -1,5 +1,5 @@
// Swap two elements of an array.
function swap(mut a: [u32; 2], i: u32, j: u32) -> [u32; 2] {
function swap(mut a: [u32; 2], const i: u32, const j: u32) -> [u32; 2] {
let t = a[i];
a[i] = a[j];
a[j] = t;

View File

@ -23,6 +23,7 @@ use std::fmt;
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct FunctionInputVariable {
pub identifier: Identifier,
pub const_: bool,
pub mutable: bool,
pub type_: Type,
pub span: Span,
@ -32,6 +33,7 @@ impl<'ast> From<GrammarFunctionInput<'ast>> for FunctionInputVariable {
fn from(parameter: GrammarFunctionInput<'ast>) -> Self {
FunctionInputVariable {
identifier: Identifier::from(parameter.identifier),
const_: parameter.const_.is_some(),
mutable: parameter.mutable.is_some(),
type_: Type::from(parameter.type_),
span: Span::from(parameter.span),
@ -42,6 +44,9 @@ impl<'ast> From<GrammarFunctionInput<'ast>> for FunctionInputVariable {
impl FunctionInputVariable {
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
// mut var: bool
if self.mutable {
write!(f, "const ")?;
}
if self.mutable {
write!(f, "mut ")?;
}

View File

@ -52,7 +52,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
None
};
if function.arguments.len() != arguments.len() {
if function.function.arguments.len() != arguments.len() {
return Err(FunctionError::input_not_found(
"arguments length invalid".to_string(),
function.span.clone().unwrap_or_default(),
@ -60,7 +60,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
}
// Store input values as new variables in resolved program
for (variable, input_expression) in function.arguments.iter().zip(arguments.iter()) {
for (variable, input_expression) in function.function.arguments.iter().zip(arguments.iter()) {
let input_value = self.enforce_expression(cs, input_expression)?;
let variable = variable.borrow();

View File

@ -64,7 +64,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
let mut arguments = vec![];
for input_variable in function.arguments.iter() {
for input_variable in function.function.arguments.iter() {
{
let input_variable = input_variable.borrow();
let name = input_variable.name.name.clone();
@ -73,7 +73,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
})?;
let input_value = self.allocate_main_function_input(
cs,
&input_variable.type_,
&input_variable.type_.clone().strong(),
&name,
input_option,
&function.span.clone().unwrap_or_default(),

View File

@ -7,7 +7,7 @@ circuit PedersenHash {
}
function hash(self, bits: [bool; 256]) -> group {
let mut digest: group = 0;
let mut digest: group = 0group;
for i in 0..256 {
if bits[i] {
digest += self.parameters[i];

View File

@ -16,7 +16,7 @@
use crate::{
ast::Rule,
common::{Identifier, Mutable},
common::{Const, Identifier, Mutable},
types::Type,
SpanDef,
};
@ -28,6 +28,7 @@ use serde::Serialize;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::function_input))]
pub struct FunctionInput<'ast> {
pub const_: Option<Const>,
pub mutable: Option<Mutable>,
pub identifier: Identifier<'ast>,
pub type_: Type<'ast>,

View File

@ -430,7 +430,7 @@ statement_return = { "return " ~ expression}
function = { "function " ~ identifier ~ input_tuple ~ ("->" ~ type_)? ~ block }
// Declared in functions/input/function_input.rs
function_input = { mutable? ~ identifier ~ ":" ~ type_ }
function_input = { const_? ~ mutable? ~ identifier ~ ":" ~ type_ }
// Declared in functions/input/input_keyword.rs
input_keyword = { "input" }