basic use case works, need to clean up, and test more advanced use cases

This commit is contained in:
gluax 2021-02-23 14:38:50 -05:00
parent 0b22e77301
commit f7314625ff
14 changed files with 355 additions and 72 deletions

View File

@ -14,7 +14,18 @@
// 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, Circuit, Expression, Function, PartialType, Scope, Span, Statement, Variable};
use crate::{
AsgConvertError,
Circuit,
Expression,
Function,
GlobalConst,
PartialType,
Scope,
Span,
Statement,
Variable,
};
/// A node in the abstract semantic graph.
pub trait Node {
@ -38,4 +49,5 @@ pub enum ArenaNode<'a> {
Variable(Variable<'a>),
Circuit(Circuit<'a>),
Function(Function<'a>),
GlobalConst(GlobalConst<'a>),
}

View File

@ -14,24 +14,94 @@
// 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, ExpressionStatement, Identifier, Node, Scope, Span, Type};
use crate::{
AsgConvertError,
Expression,
ExpressionNode,
FromAst,
InnerVariable,
Node,
Scope,
Span,
Statement,
Variable,
};
use uuid::Uuid;
use std::cell::{Cell, RefCell};
#[derive(Clone)]
pub struct Define<'a> {
pub id: Uuid,
pub name: Identifier,
pub expression: ExpressionStatement<'a>,
pub struct GlobalConst<'a> {
pub parent: Cell<Option<&'a Statement<'a>>>,
pub span: Option<Span>,
pub variable: &'a Variable<'a>,
pub value: Cell<&'a Expression<'a>>,
}
impl<'a> PartialEq for Define<'a> {
fn eq(&self, other: &Define) -> bool {
if self.name != other.name {
return false;
}
self.id == other.id
impl<'a> Node for GlobalConst<'a> {
fn span(&self) -> Option<&Span> {
self.span.as_ref()
}
}
impl<'a> Eq for Define<'a> {}
impl<'a> GlobalConst<'a> {
pub(super) fn init(
scope: &'a Scope<'a>,
global_const: &leo_ast::GlobalConst,
) -> Result<&'a GlobalConst<'a>, AsgConvertError> {
let type_ = global_const
.type_
.as_ref()
.map(|x| scope.resolve_ast_type(&x))
.transpose()?;
let value = <&Expression<'a>>::from_ast(scope, &global_const.value, type_.clone().map(Into::into))?;
let type_ = type_.or_else(|| value.get_type());
let variable = scope.alloc_variable(RefCell::new(InnerVariable {
id: uuid::Uuid::new_v4(),
name: global_const.variable_name.identifier.clone(),
type_: type_.ok_or_else(|| {
AsgConvertError::unresolved_type(&global_const.variable_name.identifier.name, &global_const.span)
})?,
mutable: global_const.variable_name.mutable,
const_: false,
declaration: crate::VariableDeclaration::Definition,
references: vec![],
assignments: vec![],
}));
//TODO add scope onto this for reference other global consts?
let global_const = scope.alloc_global_const(GlobalConst {
parent: Cell::new(None),
span: Some(global_const.span.clone()),
variable,
value: Cell::new(value),
});
Ok(global_const)
}
}
impl<'a> Into<leo_ast::GlobalConst> for &GlobalConst<'a> {
fn into(self) -> leo_ast::GlobalConst {
let mut type_ = None::<leo_ast::Type>;
let variable = self.variable.borrow();
let variable_name = leo_ast::VariableName {
mutable: variable.mutable,
identifier: variable.name.clone(),
span: variable.name.span.clone(),
};
if type_.is_none() {
type_ = Some((&variable.type_.clone()).into());
}
leo_ast::GlobalConst {
declaration_type: leo_ast::Declare::Let,
variable_name,
type_,
value: self.value.get().into(),
span: self.span.clone().unwrap_or_default(),
}
}
}

View File

@ -25,7 +25,7 @@ mod function;
pub use function::*;
mod global_const;
pub use global_const::*;
pub use global_const::*;
use crate::{ArenaNode, AsgContext, AsgConvertError, ImportResolver, Input, Scope};
use leo_ast::{Identifier, PackageAccess, PackageOrPackages, Span};
@ -55,11 +55,13 @@ pub struct InternalProgram<'a> {
/// Maps function name => function code block.
pub functions: IndexMap<String, &'a Function<'a>>,
/// Maps global constant name => global const code block.
pub global_consts: IndexMap<String, &'a GlobalConst<'a>>,
/// Maps circuit name => circuit code block.
pub circuits: IndexMap<String, &'a Circuit<'a>>,
// pub global_consts: IndexMap<String, (Identifier, &'a ExpressionStatement<'a>)>,
/// Bindings for names and additional program context.
pub scope: &'a Scope<'a>,
}
@ -179,6 +181,8 @@ impl<'a> InternalProgram<'a> {
let mut imported_functions: IndexMap<String, &'a Function<'a>> = IndexMap::new();
let mut imported_circuits: IndexMap<String, &'a Circuit<'a>> = IndexMap::new();
//TODO
let imported_global_consts: IndexMap<String, &'a GlobalConst<'a>> = IndexMap::new();
// Prepare locally relevant scope of imports.
for (package, symbol, span) in imported_symbols.into_iter() {
@ -226,9 +230,9 @@ impl<'a> InternalProgram<'a> {
circuit_self: Cell::new(None),
variables: RefCell::new(IndexMap::new()),
functions: RefCell::new(imported_functions),
global_consts: RefCell::new(imported_global_consts),
circuits: RefCell::new(imported_circuits),
function: Cell::new(None),
// global_consts: RefCell::new(Vec::new()),
input: Cell::new(None),
})) {
ArenaNode::Scope(c) => c,
@ -243,7 +247,7 @@ impl<'a> InternalProgram<'a> {
circuit_self: Cell::new(None),
variables: RefCell::new(IndexMap::new()),
functions: RefCell::new(IndexMap::new()),
// global_consts: RefCell(vec![]),
global_consts: RefCell::new(IndexMap::new()),
circuits: RefCell::new(IndexMap::new()),
function: Cell::new(None),
});
@ -271,6 +275,23 @@ impl<'a> InternalProgram<'a> {
scope.functions.borrow_mut().insert(name.name.clone(), function);
}
for (name, global_const) in program.global_consts.iter() {
assert_eq!(name.name, global_const.variable_name.identifier.name);
let gc = GlobalConst::init(scope, global_const)?;
scope.global_consts.borrow_mut().insert(name.name.clone(), gc);
}
let mut global_consts = IndexMap::new();
for (name, global_const) in program.global_consts.iter() {
assert_eq!(name.name, global_const.variable_name.identifier.name);
let asg_global_const = *scope.global_consts.borrow().get(&name.name).unwrap();
//TODO?
// asg_global_const.fill_from_ast(global_const)?;
global_consts.insert(name.name.clone(), asg_global_const);
}
// Load concrete definitions.
let mut test_functions = IndexMap::new();
for (name, test_function) in program.tests.iter() {
@ -302,19 +323,14 @@ impl<'a> InternalProgram<'a> {
circuits.insert(name.name.clone(), asg_circuit);
}
// let global_consts = vec![];
for (global_const) in program.global_consts.iter() {
// assert_eq!(name.name, define.name.name);
}
Ok(InternalProgram {
context: arena,
id: Uuid::new_v4(),
name: program.name.clone(),
test_functions,
functions,
global_consts,
circuits,
// global_consts,
imported_modules: resolved_packages
.into_iter()
.map(|(package, program)| (package.join("."), program))
@ -364,6 +380,7 @@ pub fn reform_ast<'a>(program: &Program<'a>) -> leo_ast::Program {
let mut all_circuits: IndexMap<String, &'a Circuit<'a>> = IndexMap::new();
let mut all_functions: IndexMap<String, &'a Function<'a>> = IndexMap::new();
let mut all_global_consts: IndexMap<String, &'a GlobalConst<'a>> = IndexMap::new();
let mut all_test_functions: IndexMap<String, (&'a Function<'a>, Option<Identifier>)> = IndexMap::new();
let mut identifiers = InternalIdentifierGenerator { next: 0 };
for (_, program) in all_programs.into_iter() {
@ -381,6 +398,11 @@ pub fn reform_ast<'a>(program: &Program<'a>) -> leo_ast::Program {
function.name.borrow_mut().name = identifier.clone();
all_functions.insert(identifier, *function);
}
for (name, global_const) in program.global_consts.iter() {
let identifier = format!("{}{}", identifiers.next().unwrap(), name);
global_const.variable.borrow_mut().name.name = identifier.clone();
all_global_consts.insert(identifier, *global_const);
}
for (name, function) in program.test_functions.iter() {
let identifier = format!("{}{}", identifiers.next().unwrap(), name);
function.0.name.borrow_mut().name = identifier.clone();
@ -419,7 +441,10 @@ pub fn reform_ast<'a>(program: &Program<'a>) -> leo_ast::Program {
.into_iter()
.map(|(_, circuit)| (circuit.name.borrow().clone(), circuit.into()))
.collect(),
global_consts: Vec::new(),
global_consts: all_global_consts
.into_iter()
.map(|(_, global_const)| (global_const.variable.borrow().name.clone(), global_const.into()))
.collect(),
}
}
@ -449,7 +474,11 @@ impl<'a> Into<leo_ast::Program> for &InternalProgram<'a> {
})
})
.collect(),
global_consts: Vec::new(),
global_consts: self
.global_consts
.iter()
.map(|(_, global_const)| (global_const.variable.borrow().name.clone(), (*global_const).into()))
.collect(),
}
}
}

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::{ArenaNode, AsgConvertError, Circuit, Expression, Function, Input, Statement, Type, Variable};
use crate::{ArenaNode, AsgConvertError, Circuit, Expression, Function, GlobalConst, Input, Statement, Type, Variable};
use indexmap::IndexMap;
use std::cell::{Cell, RefCell};
@ -44,6 +44,9 @@ pub struct Scope<'a> {
/// Maps function name => function.
pub functions: RefCell<IndexMap<String, &'a Function<'a>>>,
/// Maps global constant name => global const code block.
pub global_consts: RefCell<IndexMap<String, &'a GlobalConst<'a>>>,
/// Maps circuit name => circuit.
pub circuits: RefCell<IndexMap<String, &'a Circuit<'a>>>,
@ -95,6 +98,13 @@ impl<'a> Scope<'a> {
}
}
pub fn alloc_global_const(&'a self, global_const: GlobalConst<'a>) -> &'a mut GlobalConst<'a> {
match self.arena.alloc(ArenaNode::GlobalConst(global_const)) {
ArenaNode::GlobalConst(e) => e,
_ => unimplemented!(),
}
}
///
/// Returns a reference to the variable corresponding to the name.
///
@ -104,6 +114,8 @@ impl<'a> Scope<'a> {
pub fn resolve_variable(&self, name: &str) -> Option<&'a Variable<'a>> {
if let Some(resolved) = self.variables.borrow().get(name) {
Some(*resolved)
} else if let Some(resolved) = self.global_consts.borrow().get(name) {
Some(resolved.variable)
} else if let Some(scope) = self.parent_scope.get() {
scope.resolve_variable(name)
} else {
@ -205,6 +217,7 @@ impl<'a> Scope<'a> {
variables: RefCell::new(IndexMap::new()),
functions: RefCell::new(IndexMap::new()),
circuits: RefCell::new(IndexMap::new()),
global_consts: RefCell::new(IndexMap::new()),
function: Cell::new(None),
input: Cell::new(None),
})

View File

@ -14,8 +14,13 @@
// 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, Node, Span, statements::{Declare, VariableName}, Type};
use leo_grammar::global_consts::GlobalConst as GrammarGlobalConst;
use crate::{
statements::{Declare, VariableName},
Expression,
Node,
Span,
Type,
};
use serde::{Deserialize, Serialize};
use std::fmt;
@ -23,7 +28,7 @@ use std::fmt;
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
pub struct GlobalConst {
pub declaration_type: Declare,
pub variable_names: Vec<VariableName>,
pub variable_name: VariableName,
pub type_: Option<Type>,
pub value: Expression,
pub span: Span,
@ -31,21 +36,7 @@ pub struct GlobalConst {
impl fmt::Display for GlobalConst {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} ", self.declaration_type)?;
if self.variable_names.len() == 1 {
// mut a
write!(f, "{}", self.variable_names[0])?;
} else {
// (a, mut b)
let names = self
.variable_names
.iter()
.map(|x| x.to_string())
.collect::<Vec<_>>()
.join(",");
write!(f, "({})", names)?;
}
write!(f, "{} {}", self.declaration_type, self.variable_name)?;
if self.type_.is_some() {
write!(f, ": {}", self.type_.as_ref().unwrap())?;
@ -54,27 +45,6 @@ impl fmt::Display for GlobalConst {
}
}
impl<'ast> From<GrammarGlobalConst<'ast>> for GlobalConst {
fn from(statement: GrammarGlobalConst<'ast>) -> Self {
let variable_names = statement
.variables
.names
.into_iter()
.map(VariableName::from)
.collect::<Vec<_>>();
let type_ = statement.variables.type_.map(Type::from);
GlobalConst {
declaration_type: Declare::Const,
variable_names,
type_,
value: Expression::from(statement.expression),
span: Span::from(statement.span),
}
}
}
impl Node for GlobalConst {
fn span(&self) -> &Span {
&self.span

View File

@ -0,0 +1,123 @@
// 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::{
statements::{Declare, VariableName},
Expression,
GlobalConst,
Node,
Span,
Type,
};
use leo_grammar::global_consts::GlobalConst as GrammarGlobalConst;
use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
pub struct GlobalConsts {
pub declaration_type: Declare,
pub variable_names: Vec<VariableName>,
pub type_: Option<Type>,
pub value: Expression,
pub span: Span,
}
impl GlobalConsts {
pub fn into_global_const(self) -> Vec<GlobalConst> {
let mut global_consts = vec![];
let mut types: Vec<Option<Type>> = vec![];
if self.type_.is_some() {
match self.type_.clone().unwrap() {
Type::Tuple(types_old) => {
for type_ in &types_old {
types.push(Some(type_.clone()));
}
}
_ => types.push(self.type_.clone()),
}
}
for (i, variable_name) in self.variable_names.iter().enumerate() {
global_consts.push(GlobalConst {
declaration_type: self.declaration_type.clone(),
variable_name: variable_name.clone(),
type_: types.get(i).unwrap_or(&None).clone(),
value: self.value.clone(),
span: self.span.clone(),
});
}
global_consts
}
}
impl fmt::Display for GlobalConsts {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} ", self.declaration_type)?;
if self.variable_names.len() == 1 {
// mut a
write!(f, "{}", self.variable_names[0])?;
} else {
// (a, mut b)
let names = self
.variable_names
.iter()
.map(|x| x.to_string())
.collect::<Vec<_>>()
.join(",");
write!(f, "({})", names)?;
}
if self.type_.is_some() {
write!(f, ": {}", self.type_.as_ref().unwrap())?;
}
write!(f, " = {};", self.value)
}
}
impl<'ast> From<GrammarGlobalConst<'ast>> for GlobalConsts {
fn from(global_const: GrammarGlobalConst<'ast>) -> Self {
let variable_names = global_const
.variables
.names
.into_iter()
.map(VariableName::from)
.collect::<Vec<_>>();
let type_ = global_const.variables.type_.map(Type::from);
GlobalConsts {
declaration_type: Declare::Const,
variable_names,
type_,
value: Expression::from(global_const.expression),
span: Span::from(global_const.span),
}
}
}
impl Node for GlobalConsts {
fn span(&self) -> &Span {
&self.span
}
fn set_span(&mut self, span: Span) {
self.span = span;
}
}

View File

@ -16,3 +16,6 @@
pub mod global_const;
pub use global_const::*;
pub mod global_consts;
pub use global_consts::*;

View File

@ -20,10 +20,11 @@
use crate::{
load_annotation,
Circuit,
GlobalConst,
DeprecatedError,
Function,
FunctionInput,
GlobalConst,
GlobalConsts,
Identifier,
ImportStatement,
TestFunction,
@ -41,7 +42,7 @@ pub struct Program {
pub expected_input: Vec<FunctionInput>,
pub imports: Vec<ImportStatement>,
pub circuits: IndexMap<Identifier, Circuit>,
pub global_consts: Vec<GlobalConst>,
pub global_consts: IndexMap<Identifier, GlobalConst>,
pub functions: IndexMap<Identifier, Function>,
pub tests: IndexMap<Identifier, TestFunction>,
}
@ -78,7 +79,7 @@ impl<'ast> Program {
pub fn from(program_name: &str, program_ast: &File<'ast>) -> Result<Self, DeprecatedError> {
let mut imports = vec![];
let mut circuits = IndexMap::new();
let mut global_consts = vec![];
let mut global_consts = IndexMap::new();
let mut functions = IndexMap::new();
let mut tests = IndexMap::new();
let mut expected_input = vec![];
@ -98,7 +99,10 @@ impl<'ast> Program {
None
}
Definition::GlobalConst(global_const) => {
global_consts.push(GlobalConst::from(global_const));
let global_const_vec = GlobalConsts::from(global_const).into_global_const();
for gc in global_const_vec {
global_consts.insert(gc.variable_name.identifier.clone(), gc);
}
None
}
Definition::Function(function_def) => {
@ -149,7 +153,7 @@ impl Program {
expected_input: vec![],
imports: vec![],
circuits: IndexMap::new(),
global_consts: vec![],
global_consts: IndexMap::new(),
functions: IndexMap::new(),
tests: IndexMap::new(),
}

View File

@ -36,6 +36,13 @@ pub fn generate_constraints<'a, F: PrimeField, G: GroupType<F>, CS: ConstraintSy
let program = asg.as_repr();
let mut resolved_program = ConstrainedProgram::<F, G>::new(program.clone());
for (_, global_const) in program.global_consts.iter() {
let value = resolved_program
.enforce_expression(cs, global_const.value.get())
.unwrap();
resolved_program.store_global_const(global_const, value);
}
let main = {
let program = program;
program.functions.get("main").cloned()

View File

@ -26,6 +26,7 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
pub fn evaluate_ref(&mut self, variable_ref: &VariableRef) -> Result<ConstrainedValue<'a, F, G>, ExpressionError> {
// Evaluate the identifier name in the current function scope
let variable = variable_ref.variable.borrow();
let result_value = if let Some(value) = self.get(&variable.id) {
value.clone()
} else {

View File

@ -0,0 +1,30 @@
// 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/>.
//! Stores all defined names in a compiled Leo program.
use crate::{program::ConstrainedProgram, value::ConstrainedValue, GroupType};
use leo_asg::GlobalConst;
use snarkvm_models::curves::PrimeField;
impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
pub fn store_global_const(&mut self, global_const: &GlobalConst, value: ConstrainedValue<'a, F, G>) {
let variable = global_const.variable.borrow();
self.store(variable.id, value);
}
}

View File

@ -0,0 +1,18 @@
// 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/>.
pub mod global_const;
pub use self::global_const::*;

View File

@ -41,6 +41,9 @@ pub use self::expression::*;
pub mod function;
pub use self::function::*;
pub mod global_const;
pub use self::global_const::*;
pub mod output;
pub use self::output::*;

View File

@ -17,9 +17,9 @@
use crate::{
ast::Rule,
circuits::Circuit,
global_consts::GlobalConst,
definitions::{AnnotatedDefinition, Deprecated},
functions::Function,
global_consts::GlobalConst,
imports::Import,
};