mirror of
https://github.com/AleoHQ/leo.git
synced 2024-12-01 18:56:38 +03:00
251 lines
8.4 KiB
Rust
251 lines
8.4 KiB
Rust
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
|
// This file is part of the Leo library.
|
|
|
|
// The Leo library is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
|
|
// The Leo library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
|
|
// 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::{
|
|
AsgConvertError,
|
|
BlockStatement,
|
|
Circuit,
|
|
FromAst,
|
|
Identifier,
|
|
InnerScope,
|
|
MonoidalDirector,
|
|
ReturnPathReducer,
|
|
Scope,
|
|
Span,
|
|
Statement,
|
|
Type,
|
|
Variable,
|
|
WeakType,
|
|
};
|
|
use leo_ast::FunctionInput;
|
|
|
|
use std::{
|
|
cell::RefCell,
|
|
sync::{Arc, Weak},
|
|
};
|
|
use uuid::Uuid;
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
pub enum FunctionQualifier {
|
|
SelfRef,
|
|
MutSelfRef,
|
|
Static,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct Function {
|
|
pub id: Uuid,
|
|
pub name: RefCell<Identifier>,
|
|
pub output: WeakType,
|
|
pub has_input: bool,
|
|
pub argument_types: Vec<WeakType>,
|
|
pub circuit: RefCell<Option<Weak<Circuit>>>,
|
|
pub body: RefCell<Weak<FunctionBody>>,
|
|
pub qualifier: FunctionQualifier,
|
|
}
|
|
|
|
impl PartialEq for Function {
|
|
fn eq(&self, other: &Function) -> bool {
|
|
if self.name.borrow().name != other.name.borrow().name {
|
|
return false;
|
|
}
|
|
self.id == other.id
|
|
}
|
|
}
|
|
impl Eq for Function {}
|
|
|
|
#[derive(Debug)]
|
|
pub struct FunctionBody {
|
|
pub span: Option<Span>,
|
|
pub function: Arc<Function>,
|
|
pub arguments: Vec<Variable>,
|
|
pub body: Arc<Statement>,
|
|
pub scope: Scope,
|
|
}
|
|
|
|
impl PartialEq for FunctionBody {
|
|
fn eq(&self, other: &FunctionBody) -> bool {
|
|
self.function == other.function
|
|
}
|
|
}
|
|
impl Eq for FunctionBody {}
|
|
|
|
impl Function {
|
|
pub(crate) fn from_ast(scope: &Scope, value: &leo_ast::Function) -> Result<Function, AsgConvertError> {
|
|
let output: Type = value
|
|
.output
|
|
.as_ref()
|
|
.map(|t| scope.borrow().resolve_ast_type(t))
|
|
.transpose()?
|
|
.unwrap_or_else(|| Type::Tuple(vec![]));
|
|
let mut qualifier = FunctionQualifier::Static;
|
|
let mut has_input = false;
|
|
|
|
let mut argument_types = vec![];
|
|
{
|
|
for input in value.input.iter() {
|
|
match input {
|
|
FunctionInput::InputKeyword(_) => {
|
|
has_input = true;
|
|
}
|
|
FunctionInput::SelfKeyword(_) => {
|
|
qualifier = FunctionQualifier::SelfRef;
|
|
}
|
|
FunctionInput::MutSelfKeyword(_) => {
|
|
qualifier = FunctionQualifier::MutSelfRef;
|
|
}
|
|
FunctionInput::Variable(leo_ast::FunctionInputVariable { type_, .. }) => {
|
|
argument_types.push(scope.borrow().resolve_ast_type(&type_)?.into());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if qualifier != FunctionQualifier::Static && scope.borrow().circuit_self.is_none() {
|
|
return Err(AsgConvertError::invalid_self_in_global(&value.span));
|
|
}
|
|
Ok(Function {
|
|
id: Uuid::new_v4(),
|
|
name: RefCell::new(value.identifier.clone()),
|
|
output: output.into(),
|
|
has_input,
|
|
argument_types,
|
|
circuit: RefCell::new(None),
|
|
body: RefCell::new(Weak::new()),
|
|
qualifier,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl FunctionBody {
|
|
pub(super) fn from_ast(
|
|
scope: &Scope,
|
|
value: &leo_ast::Function,
|
|
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 {
|
|
let circuit = function.circuit.borrow();
|
|
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()),
|
|
mutable: function.qualifier == FunctionQualifier::MutSelfRef,
|
|
declaration: crate::VariableDeclaration::Parameter,
|
|
references: vec![],
|
|
assignments: vec![],
|
|
}));
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
let main_block = BlockStatement::from_ast(&new_scope, &value.block, None)?;
|
|
let mut director = MonoidalDirector::new(ReturnPathReducer::new());
|
|
if !director.reduce_block(&main_block).0 && !function.output.is_unit() {
|
|
return Err(AsgConvertError::function_missing_return(
|
|
&function.name.borrow().name,
|
|
&value.span,
|
|
));
|
|
}
|
|
|
|
#[allow(clippy::never_loop)] // TODO @Protryon: How should we return multiple errors?
|
|
for (span, error) in director.reducer().errors {
|
|
return Err(AsgConvertError::function_return_validation(
|
|
&function.name.borrow().name,
|
|
&error,
|
|
&span,
|
|
));
|
|
}
|
|
|
|
Ok(FunctionBody {
|
|
span: Some(value.span.clone()),
|
|
function,
|
|
arguments,
|
|
body: Arc::new(Statement::Block(main_block)),
|
|
scope: new_scope,
|
|
})
|
|
}
|
|
}
|
|
|
|
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
|
|
.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(),
|
|
span: Span::default(),
|
|
})
|
|
})
|
|
.collect(),
|
|
match body.body.as_ref() {
|
|
Statement::Block(block) => block.into(),
|
|
_ => unimplemented!(),
|
|
},
|
|
body.span.clone().unwrap_or_default(),
|
|
),
|
|
None => (
|
|
vec![],
|
|
leo_ast::Block {
|
|
statements: vec![],
|
|
span: Default::default(),
|
|
},
|
|
Default::default(),
|
|
),
|
|
};
|
|
let output: Type = self.output.clone().into();
|
|
leo_ast::Function {
|
|
identifier: self.name.borrow().clone(),
|
|
input,
|
|
block: body,
|
|
output: Some((&output).into()),
|
|
span,
|
|
}
|
|
}
|
|
}
|