From ba2a7a685ca087f03b6a988b30f980d8c4137ff4 Mon Sep 17 00:00:00 2001 From: Protryon Date: Thu, 14 Jan 2021 05:19:40 -0800 Subject: [PATCH] wip --- Cargo.lock | 3 +- asg/Cargo.toml | 2 +- asg/src/expression/call.rs | 23 ++-- asg/src/expression/circuit_access.rs | 8 +- asg/src/expression/circuit_init.rs | 8 +- asg/src/import.rs | 3 +- asg/src/input.rs | 12 +- asg/src/lib.rs | 4 +- asg/src/program/circuit.rs | 15 ++- asg/src/program/function.rs | 30 ++++- asg/src/program/mod.rs | 113 +++++++++++++++-- asg/src/reducer/monoidal_director.rs | 5 +- asg/src/reducer/monoidal_reducer.rs | 2 +- asg/src/statement/assign.rs | 2 +- asg/src/type_.rs | 4 +- asg/tests/mod.rs | 15 +-- asg/tests/pass/form_ast.rs | 66 ++++++++++ asg/tests/pass/mod.rs | 1 + ast/src/circuits/circuit.rs | 6 + ast/src/program.rs | 27 ++++ compiler/Cargo.toml | 4 + compiler/src/compiler.rs | 25 +++- compiler/src/constraints/constraints.rs | 28 ++--- compiler/src/definition/definitions.rs | 18 +-- compiler/src/errors/compiler.rs | 5 + compiler/src/function/function.rs | 122 ++++++++++--------- compiler/src/function/input/input_keyword.rs | 12 +- compiler/src/function/main_function.rs | 15 ++- compiler/src/lib.rs | 3 + compiler/src/stage.rs | 5 + compiler/src/value/implicit/implicit.rs | 33 ----- compiler/src/value/implicit/mod.rs | 18 --- compiler/src/value/mod.rs | 3 - compiler/src/value/value.rs | 49 +++----- 34 files changed, 437 insertions(+), 252 deletions(-) create mode 100644 asg/tests/pass/form_ast.rs create mode 100644 compiler/src/stage.rs delete mode 100644 compiler/src/value/implicit/implicit.rs delete mode 100644 compiler/src/value/implicit/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 2c75559e02..12c0ba3c34 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1249,7 +1249,7 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "leo-asg" -version = "1.0.0" +version = "1.0.7" dependencies = [ "criterion", "indexmap", @@ -1282,6 +1282,7 @@ dependencies = [ "bincode", "hex", "indexmap", + "leo-asg", "leo-ast", "leo-core", "leo-gadgets", diff --git a/asg/Cargo.toml b/asg/Cargo.toml index 0cbb22a8d9..f0159eb1e9 100644 --- a/asg/Cargo.toml +++ b/asg/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "leo-asg" -version = "1.0.0" +version = "1.0.7" authors = [ "The Aleo Team " ] description = "ASG of the Leo programming language" homepage = "https://aleo.org" diff --git a/asg/src/expression/call.rs b/asg/src/expression/call.rs index 077e9e3dbc..55db6d404c 100644 --- a/asg/src/expression/call.rs +++ b/asg/src/expression/call.rs @@ -61,20 +61,21 @@ impl FromAst for CallExpression { Some(Type::Circuit(circuit)) => circuit, type_ => return Err(AsgConvertError::unexpected_type("circuit", type_.map(|x| x.to_string()).as_deref(), &span)), }; + let circuit_name = circuit.name.borrow().name.clone(); let member = circuit.members.borrow(); - let member = member.get(&name.name).ok_or_else(|| AsgConvertError::unresolved_circuit_member(&circuit.name.name, &name.name, &span))?; + let member = member.get(&name.name).ok_or_else(|| AsgConvertError::unresolved_circuit_member(&circuit_name, &name.name, &span))?; match member { CircuitMember::Function(body) => { if body.qualifier == FunctionQualifier::Static { - return Err(AsgConvertError::circuit_static_call_invalid(&circuit.name.name, &name.name, &span)); + return Err(AsgConvertError::circuit_static_call_invalid(&circuit_name, &name.name, &span)); } else if body.qualifier == FunctionQualifier::MutSelfRef { if !target.is_mut_ref() { - return Err(AsgConvertError::circuit_member_mut_call_invalid(&circuit.name.name, &name.name, &span)); + return Err(AsgConvertError::circuit_member_mut_call_invalid(&circuit_name, &name.name, &span)); } } (Some(target), body.clone()) }, - CircuitMember::Variable(_) => return Err(AsgConvertError::circuit_variable_call(&circuit.name.name, &name.name, &span))?, + CircuitMember::Variable(_) => return Err(AsgConvertError::circuit_variable_call(&circuit_name, &name.name, &span))?, } }, leo_ast::Expression::CircuitStaticFunctionAccess(leo_ast::CircuitStaticFunctionAccessExpression { circuit: ast_circuit, name, span }) => { @@ -83,16 +84,18 @@ impl FromAst for CallExpression { } else { return Err(AsgConvertError::unexpected_type("circuit", None, &span)); }; + let circuit_name = circuit.name.borrow().name.clone(); + let member = circuit.members.borrow(); - let member = member.get(&name.name).ok_or_else(|| AsgConvertError::unresolved_circuit_member(&circuit.name.name, &name.name, &span))?; + let member = member.get(&name.name).ok_or_else(|| AsgConvertError::unresolved_circuit_member(&circuit_name, &name.name, &span))?; match member { CircuitMember::Function(body) => { if body.qualifier != FunctionQualifier::Static { - return Err(AsgConvertError::circuit_member_call_invalid(&circuit.name.name, &name.name, &span)); + return Err(AsgConvertError::circuit_member_call_invalid(&circuit_name, &name.name, &span)); } (None, body.clone()) }, - CircuitMember::Variable(_) => return Err(AsgConvertError::circuit_variable_call(&circuit.name.name, &name.name, &span))?, + CircuitMember::Variable(_) => return Err(AsgConvertError::circuit_variable_call(&circuit_name, &name.name, &span))?, } }, _ => return Err(AsgConvertError::illegal_ast_structure("non Identifier/CircuitMemberAccess/CircuitStaticFunctionAccess as call target")), @@ -130,12 +133,12 @@ impl Into for &CallExpression { let circuit = self.function.circuit.borrow().as_ref().map(|x| x.upgrade()).flatten(); if let Some(circuit) = circuit { leo_ast::Expression::CircuitStaticFunctionAccess(leo_ast::CircuitStaticFunctionAccessExpression { - circuit: Box::new(leo_ast::Expression::Identifier(circuit.name.clone())), - name: self.function.name.clone(), + circuit: Box::new(leo_ast::Expression::Identifier(circuit.name.borrow().clone())), + name: self.function.name.borrow().clone(), span: self.span.clone().unwrap_or_default(), }) } else { - leo_ast::Expression::Identifier(self.function.name.clone()) + leo_ast::Expression::Identifier(self.function.name.borrow().clone()) } }; leo_ast::CallExpression { diff --git a/asg/src/expression/circuit_access.rs b/asg/src/expression/circuit_access.rs index 63a042091e..720257bd5c 100644 --- a/asg/src/expression/circuit_access.rs +++ b/asg/src/expression/circuit_access.rs @@ -95,10 +95,10 @@ impl FromAst for CircuitAccessExpression ) ); } else { - return Err(AsgConvertError::input_ref_needs_type(&circuit.name.name, &value.name.name, &value.span)); + return Err(AsgConvertError::input_ref_needs_type(&circuit.name.borrow().name, &value.name.name, &value.span)); } } else { - return Err(AsgConvertError::unresolved_circuit_member(&circuit.name.name, &value.name.name, &value.span)); + return Err(AsgConvertError::unresolved_circuit_member(&circuit.name.borrow().name, &value.name.name, &value.span)); } Ok(CircuitAccessExpression { @@ -127,7 +127,7 @@ impl FromAst for CircuitAccessEx if let Some(CircuitMember::Function(_)) = circuit.members.borrow().get(&value.name.name) { // okay } else { - return Err(AsgConvertError::unresolved_circuit_member(&circuit.name.name, &value.name.name, &value.span)); + return Err(AsgConvertError::unresolved_circuit_member(&circuit.name.borrow().name, &value.name.name, &value.span)); } Ok(CircuitAccessExpression { @@ -150,7 +150,7 @@ impl Into for &CircuitAccessExpression { }) } else { leo_ast::Expression::CircuitStaticFunctionAccess(leo_ast::CircuitStaticFunctionAccessExpression { - circuit: Box::new(leo_ast::Expression::Identifier(self.circuit.name.clone())), + circuit: Box::new(leo_ast::Expression::Identifier(self.circuit.name.borrow().clone())), name: self.member.clone(), span: self.span.clone().unwrap_or_default(), }) diff --git a/asg/src/expression/circuit_init.rs b/asg/src/expression/circuit_init.rs index ffb488161a..76c7bb9dbc 100644 --- a/asg/src/expression/circuit_init.rs +++ b/asg/src/expression/circuit_init.rs @@ -51,7 +51,7 @@ impl FromAst for CircuitInitExpression { match expected_type { Some(PartialType::Type(Type::Circuit(expected_circuit))) if expected_circuit == circuit => (), None => (), - Some(x) => return Err(AsgConvertError::unexpected_type(&x.to_string(), Some(&circuit.name.name), &value.span)), + Some(x) => return Err(AsgConvertError::unexpected_type(&x.to_string(), Some(&circuit.name.borrow().name), &value.span)), } let members: IndexMap<&String, (&Identifier, &leo_ast::Expression)> = value.members.iter().map(|x| (&x.identifier.name, (&x.identifier, &x.expression))).collect(); @@ -69,13 +69,13 @@ impl FromAst for CircuitInitExpression { let received = Arc::::from_ast(scope, *receiver, Some(type_.partial()))?; values.push(((*identifier).clone(), received)); } else { - return Err(AsgConvertError::missing_circuit_member(&circuit.name.name, name, &value.span)); + return Err(AsgConvertError::missing_circuit_member(&circuit.name.borrow().name, name, &value.span)); } } for (name, (identifier, _expression)) in members.iter() { if circuit_members.get(*name).is_none() { - return Err(AsgConvertError::extra_circuit_member(&circuit.name.name, *name, &identifier.span)); + return Err(AsgConvertError::extra_circuit_member(&circuit.name.borrow().name, *name, &identifier.span)); } } } @@ -92,7 +92,7 @@ impl FromAst for CircuitInitExpression { impl Into for &CircuitInitExpression { fn into(self) -> leo_ast::CircuitInitExpression { leo_ast::CircuitInitExpression { - name: self.circuit.name.clone(), + name: self.circuit.name.borrow().clone(), members: self.values.iter().map(|(name, value)| { leo_ast::CircuitVariableDefinition { identifier: name.clone(), diff --git a/asg/src/import.rs b/asg/src/import.rs index 5a90c5f73c..d38eb49950 100644 --- a/asg/src/import.rs +++ b/asg/src/import.rs @@ -1,5 +1,6 @@ use indexmap::IndexMap; use crate::{ Program, AsgConvertError }; +use std::sync::Arc; pub trait ImportResolver { fn resolve_package(&self, package_segments: &[&str]) -> Result, AsgConvertError>; @@ -18,7 +19,7 @@ pub struct CoreImportResolver<'a, T: ImportResolver + 'static>(pub &'a T); impl<'a, T: ImportResolver + 'static> ImportResolver for CoreImportResolver<'a, T> { fn resolve_package(&self, package_segments: &[&str]) -> Result, AsgConvertError> { if package_segments.len() > 0 && package_segments.get(0).unwrap() == &"core" { - crate::resolve_core_module(&*package_segments[1..].join(".")) + Ok(crate::resolve_core_module(&*package_segments[1..].join("."))?) } else { self.0.resolve_package(package_segments) } diff --git a/asg/src/input.rs b/asg/src/input.rs index fb87e01c88..77fcc69831 100644 --- a/asg/src/input.rs +++ b/asg/src/input.rs @@ -23,25 +23,25 @@ impl Input { pub fn new() -> Self { let registers = Arc::new(Circuit { id: uuid::Uuid::new_v4(), - name: Identifier::new(REGISTERS_PSUEDO_CIRCUIT.to_string()), + name: RefCell::new(Identifier::new(REGISTERS_PSUEDO_CIRCUIT.to_string())), body: RefCell::new(Weak::new()), members: RefCell::new(IndexMap::new()), }); let record = Arc::new(Circuit { id: uuid::Uuid::new_v4(), - name: Identifier::new(RECORD_PSUEDO_CIRCUIT.to_string()), + name: RefCell::new(Identifier::new(RECORD_PSUEDO_CIRCUIT.to_string())), body: RefCell::new(Weak::new()), members: RefCell::new(IndexMap::new()), }); let state = Arc::new(Circuit { id: uuid::Uuid::new_v4(), - name: Identifier::new(STATE_PSUEDO_CIRCUIT.to_string()), + name: RefCell::new(Identifier::new(STATE_PSUEDO_CIRCUIT.to_string())), body: RefCell::new(Weak::new()), members: RefCell::new(IndexMap::new()), }); let state_leaf = Arc::new(Circuit { id: uuid::Uuid::new_v4(), - name: Identifier::new(STATE_LEAF_PSUEDO_CIRCUIT.to_string()), + name: RefCell::new(Identifier::new(STATE_LEAF_PSUEDO_CIRCUIT.to_string())), body: RefCell::new(Weak::new()), members: RefCell::new(IndexMap::new()), }); @@ -54,7 +54,7 @@ impl Input { let container_circuit = Arc::new(Circuit { id: uuid::Uuid::new_v4(), - name: Identifier::new(CONTAINER_PSUEDO_CIRCUIT.to_string()), + name: RefCell::new(Identifier::new(CONTAINER_PSUEDO_CIRCUIT.to_string())), body: RefCell::new(Weak::new()), members: RefCell::new(container_members), }); @@ -80,7 +80,7 @@ impl Input { impl Circuit { pub fn is_input_psuedo_circuit(&self) -> bool { - match &*self.name.name { + match &*self.name.borrow().name { REGISTERS_PSUEDO_CIRCUIT | RECORD_PSUEDO_CIRCUIT | STATE_PSUEDO_CIRCUIT | diff --git a/asg/src/lib.rs b/asg/src/lib.rs index 2b2dd1be6d..2fc0d15044 100644 --- a/asg/src/lib.rs +++ b/asg/src/lib.rs @@ -57,9 +57,9 @@ pub fn load_ast, Y: AsRef>(path: T, content: Y) -> Result(content: leo_ast::Program, resolver: &T) -> Result { - Program::new(&content, resolver) + InnerProgram::new(&content, resolver) } pub fn load_asg(content: &str, resolver: &T) -> Result { - Program::new(&load_ast("input.leo", content)?, resolver) + InnerProgram::new(&load_ast("input.leo", content)?, resolver) } \ No newline at end of file diff --git a/asg/src/program/circuit.rs b/asg/src/program/circuit.rs index 842c608658..e3fc7d8467 100644 --- a/asg/src/program/circuit.rs +++ b/asg/src/program/circuit.rs @@ -15,9 +15,10 @@ pub enum CircuitMember { Function(Arc), } + pub struct Circuit { pub id: Uuid, - pub name: Identifier, + pub name: RefCell, pub body: RefCell>, pub members: RefCell>, } @@ -30,6 +31,7 @@ impl PartialEq for Circuit { self.id == other.id } } +impl Eq for Circuit {} pub struct CircuitBody { pub scope: Scope, @@ -38,6 +40,13 @@ pub struct CircuitBody { pub members: RefCell>, } +impl PartialEq for CircuitBody { + fn eq(&self, other: &CircuitBody) -> bool { + self.circuit == other.circuit + } +} +impl Eq for CircuitBody {} + impl Node for CircuitMemberBody { fn span(&self) -> Option<&Span> { @@ -51,7 +60,7 @@ impl Circuit { let circuit = Arc::new(Circuit { id: Uuid::new_v4(), - name: value.circuit_name.clone(), + name: RefCell::new(value.circuit_name.clone()), body: RefCell::new(Weak::new()), members: RefCell::new(IndexMap::new()), }); @@ -140,7 +149,7 @@ impl Into for &Circuit { None => vec![], }; leo_ast::Circuit { - circuit_name: self.name.clone(), + circuit_name: self.name.borrow().clone(), members, } } diff --git a/asg/src/program/function.rs b/asg/src/program/function.rs index d8eb8f19ca..e770e7e559 100644 --- a/asg/src/program/function.rs +++ b/asg/src/program/function.rs @@ -3,6 +3,7 @@ use crate::{ Identifier, Type, WeakType, Statement, Span, AsgConvertError, Block use std::sync::{ Arc, Weak }; use std::cell::RefCell; use leo_ast::FunctionInput; +use uuid::Uuid; #[derive(PartialEq)] pub enum FunctionQualifier { @@ -12,7 +13,8 @@ pub enum FunctionQualifier { } pub struct Function { - pub name: Identifier, + pub id: Uuid, + pub name: RefCell, pub output: WeakType, pub has_input: bool, pub argument_types: Vec, @@ -21,6 +23,16 @@ pub struct Function { 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 {} + pub struct FunctionBody { pub span: Option, pub function: Arc, @@ -29,6 +41,13 @@ pub struct FunctionBody { 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 { let output: Type = value.output.as_ref().map(|t| scope.borrow().resolve_ast_type(t)).transpose()? @@ -59,7 +78,8 @@ impl Function { return Err(AsgConvertError::invalid_self_in_global(&value.span)); } Ok(Function { - name: value.identifier.clone(), + id: Uuid::new_v4(), + name: RefCell::new(value.identifier.clone()), output: output.into(), has_input, argument_types, @@ -116,10 +136,10 @@ impl FunctionBody { 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.name, &value.span)); + return Err(AsgConvertError::function_missing_return(&function.name.borrow().name, &value.span)); } for (span, error) in director.reducer().errors { - return Err(AsgConvertError::function_return_validation(&function.name.name, &error, &span)); + return Err(AsgConvertError::function_return_validation(&function.name.borrow().name, &error, &span)); } Ok(FunctionBody { @@ -166,7 +186,7 @@ impl Into for &Function { }; let output: Type = self.output.clone().into(); leo_ast::Function { - identifier: self.name.clone(), + identifier: self.name.borrow().clone(), input, block: body, output: Some((&output).into()), diff --git a/asg/src/program/mod.rs b/asg/src/program/mod.rs index 3e72c4066c..c25905323c 100644 --- a/asg/src/program/mod.rs +++ b/asg/src/program/mod.rs @@ -10,18 +10,22 @@ use indexmap::{ IndexMap, IndexSet }; use std::sync::{ Arc }; use crate::{ AsgConvertError, InnerScope, Scope, ImportResolver, Input }; use std::cell::RefCell; -use leo_ast::{Package, PackageAccess, Span}; +use leo_ast::{Package, PackageAccess, Span, Identifier}; +use uuid::Uuid; #[derive(Clone)] -pub struct Program { +pub struct InnerProgram { + pub id: Uuid, pub name: String, - pub imported_modules: Vec, // these should generally not be accessed directly, but through scoped imports + pub imported_modules: IndexMap, // these should generally not be accessed directly, but through scoped imports pub test_functions: IndexMap, Option)>, // identifier = test input file pub functions: IndexMap>, pub circuits: IndexMap>, pub scope: Scope, } +pub type Program = Arc>; + enum ImportSymbol { Direct(String), Alias(String, String), // from remote -> to local @@ -60,7 +64,7 @@ fn resolve_import_package_access(output: &mut Vec<(Vec, ImportSymbol, Sp } } -impl Program { +impl InnerProgram { /* stages: @@ -106,7 +110,7 @@ impl Program { let pretty_package = package.join("."); let resolved_package = resolved_packages.get(&package).expect("could not find preloaded package"); - + let resolved_package = resolved_package.borrow(); match symbol { ImportSymbol::All => { imported_functions.extend(resolved_package.functions.clone().into_iter()); @@ -218,26 +222,111 @@ impl Program { circuits.insert(name.name.clone(), body); } - Ok(Program { + Ok(Arc::new(RefCell::new(InnerProgram { + id: Uuid::new_v4(), name: value.name.clone(), test_functions, functions, circuits, - imported_modules: resolved_packages.into_iter().map(|(_, program)| program).collect(), + imported_modules: resolved_packages.into_iter().map(|(package, program)| (package.join("."), program)).collect(), scope, - }) + }))) + } +} + +struct InternalIdentifierGenerator { + next: usize, +} + +impl Iterator for InternalIdentifierGenerator { + type Item = String; + + fn next(&mut self) -> Option { + let out = format!("$_{}_", self.next); + self.next += 1; + Some(out) + } +} + +pub fn reform_ast(program: &Program) -> leo_ast::Program { + let mut all_programs: IndexMap = IndexMap::new(); + let mut program_stack = program.borrow().imported_modules.clone(); + while let Some((module, program)) = program_stack.pop() { + if all_programs.contains_key(&module) { + continue; + } + all_programs.insert(module, program.clone()); + program_stack.extend(program.borrow().imported_modules.clone()); + } + all_programs.insert("".to_string(), program.clone()); + let core_programs: Vec<_> = all_programs.iter().filter(|(module, _)| module.starts_with("core.")).map(|x| x.clone()).collect(); + all_programs.retain(|module, _| !module.starts_with("core.")); + + let mut all_circuits: IndexMap> = IndexMap::new(); + let mut all_functions: IndexMap> = IndexMap::new(); + let mut all_test_functions: IndexMap, Option)> = IndexMap::new(); + let mut identifiers = InternalIdentifierGenerator { next: 0 }; + for (module, program) in all_programs.into_iter() { + let program = program.borrow(); + for (name, circuit) in program.circuits.iter() { + let identifier = format!("{}{}", identifiers.next().unwrap(), name); + circuit.circuit.name.borrow_mut().name = identifier.clone(); + all_circuits.insert(identifier, circuit.clone()); + } + for (name, function) in program.functions.iter() { + let identifier = if name == "main" { + "main".to_string() + } else { + format!("{}{}", identifiers.next().unwrap(), name) + }; + function.function.name.borrow_mut().name = identifier.clone(); + all_functions.insert(identifier, function.clone()); + } + for (name, function) in program.test_functions.iter() { + let identifier = format!("{}{}", identifiers.next().unwrap(), name); + function.0.function.name.borrow_mut().name = identifier.clone(); + all_test_functions.insert(identifier, function.clone()); + } + } + + //todo: core imports + leo_ast::Program { + name: "ast_aggregate".to_string(), + imports: vec![], + expected_input: vec![], + tests: all_test_functions.into_iter().map(|(name, (function, ident))| { + ( + function.function.name.borrow().clone(), + leo_ast::TestFunction { + function: function.function.as_ref().into(), + input_file: ident, + } + ) + }).collect(), + functions: all_functions.into_iter().map(|(name, function)| { + ( + function.function.name.borrow().clone(), + function.function.as_ref().into(), + ) + }).collect(), + circuits: all_circuits.into_iter().map(|(name, circuit)| { + ( + circuit.circuit.name.borrow().clone(), + circuit.circuit.as_ref().into(), + ) + }).collect(), } } -impl Into for &Program { +impl Into for &InnerProgram { fn into(self) -> leo_ast::Program { leo_ast::Program { name: self.name.clone(), imports: vec![], expected_input: vec![], - circuits: self.circuits.iter().map(|(_, circuit)| (circuit.circuit.name.clone(), circuit.circuit.as_ref().into())).collect(), - functions: self.functions.iter().map(|(_, function)| (function.function.name.clone(), function.function.as_ref().into())).collect(), - tests: self.test_functions.iter().map(|(_, function)| (function.0.function.name.clone(), leo_ast::TestFunction { + circuits: self.circuits.iter().map(|(_, circuit)| (circuit.circuit.name.borrow().clone(), circuit.circuit.as_ref().into())).collect(), + functions: self.functions.iter().map(|(_, function)| (function.function.name.borrow().clone(), function.function.as_ref().into())).collect(), + tests: self.test_functions.iter().map(|(_, function)| (function.0.function.name.borrow().clone(), leo_ast::TestFunction { function: function.0.function.as_ref().into(), input_file: function.1.clone(), })).collect(), diff --git a/asg/src/reducer/monoidal_director.rs b/asg/src/reducer/monoidal_director.rs index b15e16a017..abc7fa2e68 100644 --- a/asg/src/reducer/monoidal_director.rs +++ b/asg/src/reducer/monoidal_director.rs @@ -250,11 +250,12 @@ impl> MonoidalDirector { } fn reduce_program(&mut self, input: &Program) -> T { - let imported_modules = input.imported_modules.iter().map(|import| self.reduce_program(import)).collect(); + let input = input.borrow(); + let imported_modules = input.imported_modules.iter().map(|(_, import)| self.reduce_program(import)).collect(); let test_functions = input.test_functions.iter().map(|(_, (f, _))| self.reduce_function(f)).collect(); let functions = input.functions.iter().map(|(_, f)| self.reduce_function(f)).collect(); let circuits = input.circuits.iter().map(|(_, c)| self.reduce_circuit(c)).collect(); - self.reducer.reduce_program(input, imported_modules, test_functions, functions, circuits) + self.reducer.reduce_program(&input, imported_modules, test_functions, functions, circuits) } } diff --git a/asg/src/reducer/monoidal_reducer.rs b/asg/src/reducer/monoidal_reducer.rs index cf7fe4fa67..0191ef9ac8 100644 --- a/asg/src/reducer/monoidal_reducer.rs +++ b/asg/src/reducer/monoidal_reducer.rs @@ -130,7 +130,7 @@ pub trait MonoidalReducerProgram: MonoidalReducerStatement { T::default().append_all(members.into_iter()) } - fn reduce_program(&mut self, input: &Program, imported_modules: Vec, test_functions: Vec, functions: Vec, circuits: Vec) -> T { + fn reduce_program(&mut self, input: &InnerProgram, imported_modules: Vec, test_functions: Vec, functions: Vec, circuits: Vec) -> T { T::default() .append_all(imported_modules.into_iter()) .append_all(test_functions.into_iter()) diff --git a/asg/src/statement/assign.rs b/asg/src/statement/assign.rs index 8a9fcd9ff2..e4bd1d08c7 100644 --- a/asg/src/statement/assign.rs +++ b/asg/src/statement/assign.rs @@ -114,7 +114,7 @@ impl FromAst for Arc { let circuit = circuit; let members = circuit.members.borrow(); - let member = members.get(&name.name).ok_or_else(|| AsgConvertError::unresolved_circuit_member(&circuit.name.name, &name.name, &statement.span))?; + let member = members.get(&name.name).ok_or_else(|| AsgConvertError::unresolved_circuit_member(&circuit.name.borrow().name, &name.name, &statement.span))?; let x = match &member { CircuitMember::Variable(type_) => type_.clone(), diff --git a/asg/src/type_.rs b/asg/src/type_.rs index e86157e28b..209498afd6 100644 --- a/asg/src/type_.rs +++ b/asg/src/type_.rs @@ -158,7 +158,7 @@ impl fmt::Display for Type { } write!(f, ")") }, - Type::Circuit(circuit) => write!(f, "{}", &circuit.name.name), + Type::Circuit(circuit) => write!(f, "{}", &circuit.name.borrow().name), } } } @@ -210,7 +210,7 @@ impl Into for &Type { Integer(int_type) => leo_ast::Type::IntegerType(int_type.clone()), Array(type_, len) => leo_ast::Type::Array(Box::new(type_.as_ref().into()), leo_ast::ArrayDimensions(vec![leo_ast::PositiveNumber { value: len.to_string() }])), Tuple(subtypes) => leo_ast::Type::Tuple(subtypes.iter().map(Into::into).collect()), - Circuit(circuit) => leo_ast::Type::Circuit(circuit.name.clone()), + Circuit(circuit) => leo_ast::Type::Circuit(circuit.name.borrow().clone()), } } } \ No newline at end of file diff --git a/asg/tests/mod.rs b/asg/tests/mod.rs index ea7edc77e7..8d6d0b92bd 100644 --- a/asg/tests/mod.rs +++ b/asg/tests/mod.rs @@ -1,25 +1,14 @@ use leo_asg::*; -use leo_ast::Program as AstProgram; -use leo_grammar::Grammar; -use std::path::Path; mod pass; mod fail; -fn load_ast(content: &str) -> Result { - // Parses the Leo file and constructs a grammar ast. - let ast = Grammar::new(Path::new("test.leo"), content).map_err(|e| AsgConvertError::InternalError(format!("ast: {:?}", e)))?; - - // Parses the pest ast and constructs a Leo ast. - Ok(leo_ast::Ast::new("leo_tree", &ast).into_repr()) -} - fn load_asg(content: &str) -> Result { - Program::new(&load_ast(content)?, &NullImportResolver) + leo_asg::load_asg(content, &NullImportResolver) } fn load_asg_imports(content: &str, imports: &T) -> Result { - Program::new(&load_ast(content)?, imports) + leo_asg::load_asg(content, imports) } fn mocked_resolver() -> MockedImportResolver { diff --git a/asg/tests/pass/form_ast.rs b/asg/tests/pass/form_ast.rs new file mode 100644 index 0000000000..2047d8bb7c --- /dev/null +++ b/asg/tests/pass/form_ast.rs @@ -0,0 +1,66 @@ +use crate::load_asg; + +#[test] +fn test_basic() { + let program_string = include_str!("./circuits/pedersen_mock.leo"); + let asg = load_asg(program_string).unwrap(); + let reformed_ast = leo_asg::reform_ast(&asg); + println!("{}", reformed_ast); + panic!(); +} + +#[test] +fn test_function_rename() { + let program_string = r#" + function iteration() -> u32 { + let mut a = 0u32; + + for i in 0..10 { + a += 1; + } + + return a + } + + function main() { + let total = iteration() + iteration(); + + console.assert(total == 20); + } + "#; + let asg = load_asg(program_string).unwrap(); + let reformed_ast = leo_asg::reform_ast(&asg); + println!("{}", reformed_ast); + panic!(); +} + + +#[test] +fn test_imports() { + let mut imports = crate::mocked_resolver(); + let test_import = r#" + circuit Point { + x: u32 + y: u32 + } + + function foo() -> u32 { + return 1u32 + } + "#; + imports.packages.insert("test-import".to_string(), load_asg(test_import).unwrap()); + let program_string = r#" + import test-import.foo; + + function main() { + console.assert(foo() == 1u32); + } + "#; + println!("{}", serde_json::to_string(&crate::load_ast("test-import.leo", test_import).unwrap()).unwrap()); + println!("{}", serde_json::to_string(&crate::load_ast("test.leo", program_string).unwrap()).unwrap()); + let asg = crate::load_asg_imports(program_string, &imports).unwrap(); + let reformed_ast = leo_asg::reform_ast(&asg); + println!("{}", serde_json::to_string(&reformed_ast).unwrap()); + panic!(); + +} \ No newline at end of file diff --git a/asg/tests/pass/mod.rs b/asg/tests/pass/mod.rs index 62e70208bf..5c032d920d 100644 --- a/asg/tests/pass/mod.rs +++ b/asg/tests/pass/mod.rs @@ -30,3 +30,4 @@ pub mod integers; pub mod mutability; pub mod statements; pub mod tuples; +pub mod form_ast; diff --git a/ast/src/circuits/circuit.rs b/ast/src/circuits/circuit.rs index 010f408c78..25ead98a00 100644 --- a/ast/src/circuits/circuit.rs +++ b/ast/src/circuits/circuit.rs @@ -50,3 +50,9 @@ impl fmt::Debug for Circuit { self.format(f) } } + +impl fmt::Display for Circuit { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.format(f) + } +} diff --git a/ast/src/program.rs b/ast/src/program.rs index 4794267217..1e4e31497f 100644 --- a/ast/src/program.rs +++ b/ast/src/program.rs @@ -22,6 +22,8 @@ use leo_grammar::{definitions::Definition, files::File}; use indexmap::IndexMap; use serde::{Deserialize, Serialize}; +use std::fmt; + /// Stores the Leo program abstract syntax tree. #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] pub struct Program { @@ -33,6 +35,31 @@ pub struct Program { pub tests: IndexMap, } +impl fmt::Display for Program { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + for import in self.imports.iter() { + import.fmt(f)?; + write!(f, "\n")?; + } + write!(f, "\n")?; + for (_, circuit) in self.circuits.iter() { + circuit.fmt(f)?; + write!(f, "\n")?; + } + write!(f, "\n")?; + for (_, function) in self.functions.iter() { + function.fmt(f)?; + write!(f, "\n")?; + } + for (_, test) in self.tests.iter() { + write!(f, "test ")?; + test.function.fmt(f)?; + write!(f, "\n")?; + } + write!(f, "") + } +} + const MAIN_FUNCTION_NAME: &str = "main"; impl<'ast> Program { diff --git a/compiler/Cargo.toml b/compiler/Cargo.toml index e8f513870d..4cb4fde38a 100644 --- a/compiler/Cargo.toml +++ b/compiler/Cargo.toml @@ -57,6 +57,10 @@ version = "1.0.7" path = "../type-inference" version = "1.0.7" +[dependencies.leo-asg] +path = "../asg" +version = "1.0.7" + [dependencies.snarkvm-curves] version = "0.0.2" default-features = false diff --git a/compiler/src/compiler.rs b/compiler/src/compiler.rs index e878647140..9eb7ee4665 100644 --- a/compiler/src/compiler.rs +++ b/compiler/src/compiler.rs @@ -38,6 +38,7 @@ use snarkvm_models::{ curves::{Field, PrimeField}, gadgets::r1cs::{ConstraintSynthesizer, ConstraintSystem}, }; +use leo_asg::Program as AsgProgram; use sha2::{Digest, Sha256}; use std::{ @@ -54,6 +55,7 @@ pub struct Compiler> { output_directory: PathBuf, program: Program, program_input: Input, + asg: Option, imported_programs: ImportParser, _engine: PhantomData, _group: PhantomData, @@ -70,6 +72,7 @@ impl> Compiler { output_directory, program: Program::new(package_name), program_input: Input::new(), + asg: None, imported_programs: ImportParser::default(), _engine: PhantomData, _group: PhantomData, @@ -164,7 +167,9 @@ impl> Compiler { pub(crate) fn parse_and_check_program(&mut self) -> Result<(), CompilerError> { self.parse_program()?; - self.check_program() + self.check_program()?; + + self.program_asg_generate() } /// @@ -225,6 +230,17 @@ impl> Compiler { Ok(()) } + pub(crate) fn program_asg_generate(&mut self) -> Result<(), CompilerError> { + // Create a new symbol table from the program, imported_programs, and program_input. + let asg = leo_asg::InnerProgram::new(&self.program, &leo_asg::NullImportResolver)?; + + tracing::debug!("ASG generation complete"); + + self.asg = Some(asg); + + Ok(()) + } + /// /// Equivalent to parse_and_check_program but uses the given program_string instead of a main /// file path. @@ -303,7 +319,7 @@ impl> Compiler { pub fn compile_constraints>(self, cs: &mut CS) -> Result { let path = self.main_file_path; - generate_constraints::(cs, &self.program, &self.program_input, &self.imported_programs).map_err( + generate_constraints::(cs, self.asg.as_ref().unwrap(), &self.program_input).map_err( |mut error| { error.set_path(&path); @@ -317,9 +333,8 @@ impl> Compiler { /// pub fn compile_test_constraints(self, input_pairs: InputPairs) -> Result<(u32, u32), CompilerError> { generate_test_constraints::( - self.program, + self.asg.as_ref().unwrap(), input_pairs, - &self.imported_programs, &self.main_file_path, &self.output_directory, ) @@ -333,7 +348,7 @@ impl> Compiler { cs: &mut CS, ) -> Result { let path = &self.main_file_path; - generate_constraints::<_, G, _>(cs, &self.program, &self.program_input, &self.imported_programs).map_err( + generate_constraints::<_, G, _>(cs, self.asg.as_ref().unwrap(), &self.program_input).map_err( |mut error| { error.set_path(&path); error diff --git a/compiler/src/constraints/constraints.rs b/compiler/src/constraints/constraints.rs index 4d4e1252e7..68886f4981 100644 --- a/compiler/src/constraints/constraints.rs +++ b/compiler/src/constraints/constraints.rs @@ -25,8 +25,8 @@ use crate::{ OutputBytes, OutputFile, }; -use leo_ast::{Input, Program}; -use leo_imports::ImportParser; +use leo_ast::{Input}; +use leo_asg::Program; use leo_input::LeoInputParser; use leo_package::inputs::InputPairs; @@ -40,19 +40,18 @@ pub fn generate_constraints, CS: Constrai cs: &mut CS, program: &Program, input: &Input, - imported_programs: &ImportParser, ) -> Result { let mut resolved_program = ConstrainedProgram::::new(); - let program_name = program.get_name(); + let program_name = program.borrow().name.clone(); let main_function_name = new_scope(&program_name, "main"); - resolved_program.store_definitions(program, imported_programs)?; + resolved_program.store_definitions(program)?; let main = resolved_program.get(&main_function_name).ok_or(CompilerError::NoMain)?; match main.clone() { ConstrainedValue::Function(_circuit_identifier, function) => { - let result = resolved_program.enforce_main_function(cs, &program_name, *function, input)?; + let result = resolved_program.enforce_main_function(cs, &program_name, function, input)?; Ok(result) } _ => Err(CompilerError::NoMainFunction), @@ -60,36 +59,35 @@ pub fn generate_constraints, CS: Constrai } pub fn generate_test_constraints>( - program: Program, + program: &Program, input: InputPairs, - imported_programs: &ImportParser, main_file_path: &Path, output_directory: &Path, ) -> Result<(u32, u32), CompilerError> { let mut resolved_program = ConstrainedProgram::::new(); - let program_name = program.get_name(); - - let tests = program.tests.clone(); + let program_name = program.borrow().name.clone(); // Store definitions - resolved_program.store_definitions(&program, imported_programs)?; + resolved_program.store_definitions(&program)?; // Get default input let default = input.pairs.get(&program_name); + let program = program.borrow(); + let tests = &program.test_functions; tracing::info!("Running {} tests", tests.len()); // Count passed and failed tests let mut passed = 0; let mut failed = 0; - for (test_name, test) in tests.into_iter() { + for (test_name, (function, input_file)) in tests.into_iter() { let cs = &mut TestConstraintSystem::::new(); let full_test_name = format!("{}::{}", program_name.clone(), test_name); let mut output_file_name = program_name.clone(); // get input file name from annotation or use test_name - let input_pair = match test.input_file { + let input_pair = match input_file { Some(file_id) => { let file_name = file_id.name; @@ -119,7 +117,7 @@ pub fn generate_test_constraints>( let result = resolved_program.enforce_main_function( cs, &program_name, - test.function, + function, &input, // pass program input into every test ); diff --git a/compiler/src/definition/definitions.rs b/compiler/src/definition/definitions.rs index d075c779f5..106234f6cf 100644 --- a/compiler/src/definition/definitions.rs +++ b/compiler/src/definition/definitions.rs @@ -22,8 +22,7 @@ use crate::{ value::ConstrainedValue, GroupType, }; -use leo_ast::Program; -use leo_imports::ImportParser; +use leo_asg::Program; use snarkvm_models::curves::{Field, PrimeField}; @@ -31,20 +30,13 @@ impl> ConstrainedProgram { pub fn store_definitions( &mut self, program: &Program, - imported_programs: &ImportParser, ) -> Result<(), ImportError> { + let program = program.borrow(); let program_name = program.name.trim_end_matches(".leo"); - // evaluate all import statements and store imported definitions - program - .imports - .iter() - .map(|import| self.store_import(&program_name, import, imported_programs)) - .collect::, ImportError>>()?; - // evaluate and store all circuit definitions program.circuits.iter().for_each(|(identifier, circuit)| { - let resolved_circuit_name = new_scope(program_name, &identifier.name); + let resolved_circuit_name = new_scope(program_name, &identifier); self.store( resolved_circuit_name, ConstrainedValue::CircuitDefinition(circuit.clone()), @@ -53,10 +45,10 @@ impl> ConstrainedProgram { // evaluate and store all function definitions program.functions.iter().for_each(|(function_name, function)| { - let resolved_function_name = new_scope(program_name, &function_name.name); + let resolved_function_name = new_scope(program_name, &function_name); self.store( resolved_function_name, - ConstrainedValue::Function(None, Box::new(function.clone())), + ConstrainedValue::Function(None, function.clone()), ); }); diff --git a/compiler/src/errors/compiler.rs b/compiler/src/errors/compiler.rs index 65f652de59..f2fe31e105 100644 --- a/compiler/src/errors/compiler.rs +++ b/compiler/src/errors/compiler.rs @@ -15,6 +15,7 @@ // along with the Leo library. If not, see . use crate::errors::{FunctionError, ImportError, OutputBytesError, OutputFileError}; +use leo_asg::AsgConvertError; use leo_grammar::ParserError; use leo_imports::ImportParserError; use leo_input::InputParserError; @@ -71,8 +72,12 @@ pub enum CompilerError { #[error("{}", _0)] SymbolTableError(#[from] SymbolTableError), + #[error("{}", _0)] TypeInferenceError(#[from] TypeInferenceError), + + #[error("{}", _0)] + AsgConvertError(#[from] AsgConvertError), } impl CompilerError { diff --git a/compiler/src/function/function.rs b/compiler/src/function/function.rs index 18cc1d86dc..a0a20a1a19 100644 --- a/compiler/src/function/function.rs +++ b/compiler/src/function/function.rs @@ -23,7 +23,8 @@ use crate::{ GroupType, }; -use leo_ast::{Expression, Function, FunctionInput}; +use leo_asg::{Expression, FunctionBody, FunctionQualifier}; +use std::sync::Arc; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -36,81 +37,90 @@ impl> ConstrainedProgram { cs: &mut CS, scope: &str, caller_scope: &str, - function: Function, - input: Vec, + function: &Arc, + input: Option<&Expression>, + self_: Option<&Expression>, + arguments: Vec<&Expression>, declared_circuit_reference: &str, ) -> Result, FunctionError> { - let function_name = new_scope(scope, function.get_name()); + let function_name = new_scope(scope, &function.function.name.borrow().name.clone()); // Store if function contains input `mut self`. - let mut_self = function.contains_mut_self(); + let mut_self = function.function.qualifier == FunctionQualifier::MutSelfRef; + + if function.function.has_input { + if let Some(input) = input { + // todo: enforce self & input + let value = + self.enforce_function_input(cs, scope, caller_scope, &function_name, None, input)?; + + self.store(new_scope(&function_name, "input"), value); + } else { + return Err(FunctionError::input_not_found("input".to_string(), function.span.unwrap_or_default())); + } + } - // Store input values as new variables in resolved program - for (input_model, input_expression) in function.filter_self_inputs().zip(input.into_iter()) { - let (name, value) = match input_model { - FunctionInput::InputKeyword(keyword) => { + match function.function.qualifier { + FunctionQualifier::SelfRef | FunctionQualifier::MutSelfRef => { + if let Some(input) = input { + // todo: enforce self & input let value = - self.enforce_function_input(cs, scope, caller_scope, &function_name, None, input_expression)?; - - (keyword.to_string(), value) + self.enforce_function_input(cs, scope, caller_scope, &function_name, None, self_)?; + + self.store(new_scope(&function_name, "self"), value); + } else { + return Err(FunctionError::input_not_found("self".to_string(), function.span.unwrap_or_default())); } - FunctionInput::SelfKeyword(keyword) => { - let value = - self.enforce_function_input(cs, scope, caller_scope, &function_name, None, input_expression)?; + }, + FunctionQualifier::Static => (), + } + if function.arguments.len() != arguments.len() { + return Err(FunctionError::input_not_found("arguments length invalid".to_string(), function.span.unwrap_or_default())); + } - (keyword.to_string(), value) - } - FunctionInput::MutSelfKeyword(keyword) => { - let value = - self.enforce_function_input(cs, scope, caller_scope, &function_name, None, input_expression)?; + // Store input values as new variables in resolved program + for (variable, input_expression) in function.arguments.iter().zip(arguments.into_iter()) { + let variable = variable.borrow(); - (keyword.to_string(), value) - } - FunctionInput::Variable(input_model) => { - // First evaluate input expression - let mut input_value = self.enforce_function_input( - cs, - scope, - caller_scope, - &function_name, - Some(input_model.type_.clone()), - input_expression, - )?; - - if input_model.mutable { - input_value = ConstrainedValue::Mutable(Box::new(input_value)) - } - - (input_model.identifier.name.clone(), input_value) - } - }; + let mut input_value = self.enforce_function_input( + cs, + scope, + caller_scope, + &function_name, + Some(variable.type_.clone()), + input_expression, + )?; + + if variable.mutable { + input_value = ConstrainedValue::Mutable(Box::new(input_value)) + } // Store input as variable with {function_name}_{input_name} - let input_program_identifier = new_scope(&function_name, &name); - self.store(input_program_identifier, value); + let input_program_identifier = new_scope(&function_name, &variable.name.name); + self.store(input_program_identifier, input_value); } // Evaluate every statement in the function and save all potential results let mut results = vec![]; let indicator = Boolean::constant(true); - for statement in function.block.statements.iter() { - let mut result = self.enforce_statement( - cs, - scope, - &function_name, - &indicator, - statement.clone(), - function.output.clone(), - declared_circuit_reference, - mut_self, - )?; + let output = function.function.output.clone().strong(); - results.append(&mut result); - } + let mut result = self.enforce_statement( + cs, + scope, + &function_name, + &indicator, + &function.body, + &output, + declared_circuit_reference, + mut_self, + )?; + + results.append(&mut result); // Conditionally select a result based on returned indicators - Self::conditionally_select_result(cs, function.output, results, &function.span) + Self::conditionally_select_result(cs, &output, results, &function.span.unwrap_or_default()) .map_err(FunctionError::StatementError) } } diff --git a/compiler/src/function/input/input_keyword.rs b/compiler/src/function/input/input_keyword.rs index 0f74c35b06..c424941b2d 100644 --- a/compiler/src/function/input/input_keyword.rs +++ b/compiler/src/function/input/input_keyword.rs @@ -15,7 +15,7 @@ // along with the Leo library. If not, see . use crate::{errors::FunctionError, ConstrainedCircuitMember, ConstrainedProgram, ConstrainedValue, GroupType}; -use leo_ast::{Identifier, Input, InputKeyword}; +use leo_ast::{Identifier, Input, Span}; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -31,26 +31,26 @@ impl> ConstrainedProgram { pub fn allocate_input_keyword>( &mut self, cs: &mut CS, - keyword: InputKeyword, + span: Span, input: &Input, ) -> Result, FunctionError> { // Create an identifier for each input variable let registers_name = Identifier { name: REGISTERS_VARIABLE_NAME.to_string(), - span: keyword.span.clone(), + span, }; let record_name = Identifier { name: RECORD_VARIABLE_NAME.to_string(), - span: keyword.span.clone(), + span, }; let state_name = Identifier { name: STATE_VARIABLE_NAME.to_string(), - span: keyword.span.clone(), + span, }; let state_leaf_name = Identifier { name: STATE_LEAF_VARIABLE_NAME.to_string(), - span: keyword.span.clone(), + span, }; // Fetch each input variable's definitions diff --git a/compiler/src/function/main_function.rs b/compiler/src/function/main_function.rs index d08faa169f..4c0fdf2a95 100644 --- a/compiler/src/function/main_function.rs +++ b/compiler/src/function/main_function.rs @@ -23,7 +23,9 @@ use crate::{ OutputBytes, }; -use leo_ast::{Expression, Function, FunctionInput, Identifier, Input}; +use leo_asg::{Expression, FunctionBody}; +use leo_ast::Input; +use std::sync::Arc; use snarkvm_models::{ curves::{Field, PrimeField}, @@ -35,14 +37,21 @@ impl> ConstrainedProgram { &mut self, cs: &mut CS, scope: &str, - function: Function, + function: &Arc, input: &Input, ) -> Result { - let function_name = new_scope(scope, function.get_name()); + let function_name = new_scope(scope, &function.function.name.borrow().name.clone()); let registers = input.get_registers(); // Iterate over main function input variables and allocate new values let mut input_variables = Vec::with_capacity(function.input.len()); + if function.function.has_input { + let value = self.allocate_input_keyword(cs, keyword, input)?; + + self.store(new_scope(&function_name, "input"), value); + } + + for input_model in function.input.clone().into_iter() { let (input_id, value) = match input_model { FunctionInput::InputKeyword(keyword) => { diff --git a/compiler/src/lib.rs b/compiler/src/lib.rs index 03abbf4457..b38de5b75b 100644 --- a/compiler/src/lib.rs +++ b/compiler/src/lib.rs @@ -55,3 +55,6 @@ pub use self::statement::*; pub mod value; pub use self::value::*; + +pub mod stage; +pub use self::stage::*; diff --git a/compiler/src/stage.rs b/compiler/src/stage.rs new file mode 100644 index 0000000000..bf956666c7 --- /dev/null +++ b/compiler/src/stage.rs @@ -0,0 +1,5 @@ +use leo_asg::Program; + +pub trait ASGStage { + fn apply(asg: &mut Program); +} \ No newline at end of file diff --git a/compiler/src/value/implicit/implicit.rs b/compiler/src/value/implicit/implicit.rs deleted file mode 100644 index bb8398ad87..0000000000 --- a/compiler/src/value/implicit/implicit.rs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (C) 2019-2020 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 . - -//! Enforces constraints on an implicit number in a compiled Leo program. - -use crate::{errors::ValueError, value::ConstrainedValue, GroupType}; -use leo_ast::{Span, Type}; - -use snarkvm_models::curves::{Field, PrimeField}; - -pub fn enforce_number_implicit>( - expected_type: Option, - value: String, - span: &Span, -) -> Result, ValueError> { - match expected_type { - Some(type_) => Ok(ConstrainedValue::from_type(value, &type_, span)?), - None => Ok(ConstrainedValue::Unresolved(value)), - } -} diff --git a/compiler/src/value/implicit/mod.rs b/compiler/src/value/implicit/mod.rs deleted file mode 100644 index 136af271f6..0000000000 --- a/compiler/src/value/implicit/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (C) 2019-2020 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 . - -pub mod implicit; -pub use self::implicit::*; diff --git a/compiler/src/value/mod.rs b/compiler/src/value/mod.rs index 2836c9c3dd..e68fcf8909 100644 --- a/compiler/src/value/mod.rs +++ b/compiler/src/value/mod.rs @@ -27,9 +27,6 @@ pub use self::field::*; pub mod group; pub use self::group::*; -pub mod implicit; -pub use self::implicit::*; - pub mod integer; pub use self::integer::*; diff --git a/compiler/src/value/value.rs b/compiler/src/value/value.rs index 64c344cacd..20337e75c2 100644 --- a/compiler/src/value/value.rs +++ b/compiler/src/value/value.rs @@ -26,7 +26,7 @@ use crate::{ GroupType, Integer, }; -use leo_ast::{ArrayDimensions, Circuit, Function, GroupValue, Identifier, Span, Type}; +use leo_asg::{CircuitBody, FunctionBody, GroupValue, Identifier, Span, Type}; use leo_core::Value; use snarkvm_errors::gadgets::SynthesisError; @@ -38,6 +38,7 @@ use snarkvm_models::{ }, }; use std::fmt; +use std::sync::Arc; #[derive(Clone, PartialEq, Eq)] pub struct ConstrainedCircuitMember>(pub Identifier, pub ConstrainedValue); @@ -58,19 +59,16 @@ pub enum ConstrainedValue> { Tuple(Vec>), // Circuits - CircuitDefinition(Circuit), - CircuitExpression(Identifier, Vec>), + CircuitDefinition(Arc), + CircuitExpression(Arc, Vec>), // Functions - Function(Option, Box), // (optional circuit identifier, function definition) + Function(Option, Arc), // (optional circuit identifier, function definition) // Modifiers Mutable(Box>), Static(Box>), Unresolved(String), - - // Imports - Import(String, Box>), } impl> ConstrainedValue { @@ -88,9 +86,8 @@ impl> ConstrainedValue { Type::Field => Ok(ConstrainedValue::Field(FieldType::constant(value, span)?)), Type::Group => Ok(ConstrainedValue::Group(G::constant(GroupValue::Single( value, - span.to_owned(), ))?)), - Type::IntegerType(integer_type) => Ok(ConstrainedValue::Integer(Integer::new_constant( + Type::Integer(integer_type) => Ok(ConstrainedValue::Integer(Integer::new_constant( integer_type, value, span, @@ -109,21 +106,13 @@ impl> ConstrainedValue { ConstrainedValue::Boolean(_bool) => Type::Boolean, ConstrainedValue::Field(_field) => Type::Field, ConstrainedValue::Group(_group) => Type::Group, - ConstrainedValue::Integer(integer) => Type::IntegerType(integer.get_type()), + ConstrainedValue::Integer(integer) => Type::Integer(integer.get_type()), // Data type wrappers ConstrainedValue::Array(array) => { let array_type = array[0].to_type(span)?; - let mut dimensions = ArrayDimensions::default(); - dimensions.push_usize(array.len()); - - // Nested array type - if let Type::Array(inner_type, inner_dimensions) = &array_type { - dimensions.append(&mut inner_dimensions.clone()); - return Ok(Type::Array(inner_type.clone(), dimensions)); - } - Type::Array(Box::new(array_type), dimensions) + Type::Array(Box::new(array_type), array.len()) } ConstrainedValue::Tuple(tuple) => { let mut types = Vec::with_capacity(tuple.len()); @@ -135,7 +124,7 @@ impl> ConstrainedValue { Type::Tuple(types) } - ConstrainedValue::CircuitExpression(id, _members) => Type::Circuit(id.clone()), + ConstrainedValue::CircuitExpression(id, _members) => Type::Circuit(id.circuit.clone()), ConstrainedValue::Mutable(value) => return value.to_type(span), value => return Err(ValueError::implicit(value.to_string(), span.to_owned())), }) @@ -202,7 +191,7 @@ impl> ConstrainedValue { } } - pub(crate) fn extract_function(self, scope: &str, span: &Span) -> Result<(String, Function), ExpressionError> { + pub(crate) fn extract_function(&self, scope: &str, span: &Span) -> Result<(String, Arc), ExpressionError> { match self { ConstrainedValue::Function(circuit_identifier, function) => { let mut outer_scope = scope.to_string(); @@ -214,17 +203,15 @@ impl> ConstrainedValue { } } - Ok((outer_scope, *function)) + Ok((outer_scope, function.clone())) } - ConstrainedValue::Import(import_scope, function) => function.extract_function(&import_scope, span), value => Err(ExpressionError::undefined_function(value.to_string(), span.to_owned())), } } - pub(crate) fn extract_circuit(self, span: &Span) -> Result { + pub(crate) fn extract_circuit(&self, span: &Span) -> Result, ExpressionError> { match self { - ConstrainedValue::CircuitDefinition(circuit) => Ok(circuit), - ConstrainedValue::Import(_import_scope, circuit) => circuit.extract_circuit(span), + ConstrainedValue::CircuitDefinition(circuit) => Ok(circuit.clone()), value => Err(ExpressionError::undefined_circuit(value.to_string(), span.to_owned())), } } @@ -310,7 +297,6 @@ impl> ConstrainedValue { // Empty wrappers that are unreachable ConstrainedValue::CircuitDefinition(_) => {} ConstrainedValue::Function(_, _) => {} - ConstrainedValue::Import(_, _) => {} // Cannot allocate an unresolved value ConstrainedValue::Unresolved(value) => { @@ -355,8 +341,8 @@ impl> fmt::Display for ConstrainedValue { - write!(f, "{} {{", identifier)?; + ConstrainedValue::CircuitExpression(ref circuit, ref members) => { + write!(f, "{} {{", circuit.circuit.name.borrow())?; for (i, member) in members.iter().enumerate() { write!(f, "{}: {}", member.0, member.1)?; if i < members.len() - 1 { @@ -365,11 +351,10 @@ impl> fmt::Display for ConstrainedValue write!(f, "circuit {{ {} }}", circuit.circuit_name), + ConstrainedValue::CircuitDefinition(ref circuit) => write!(f, "circuit {{ {} }}", circuit.circuit.name.borrow().name), ConstrainedValue::Function(ref _circuit_option, ref function) => { - write!(f, "function {{ {}() }}", function.identifier) + write!(f, "function {{ {}() }}", function.function.name.borrow().name) } - ConstrainedValue::Import(_, ref value) => write!(f, "{}", value), ConstrainedValue::Mutable(ref value) => write!(f, "{}", value), ConstrainedValue::Static(ref value) => write!(f, "{}", value), ConstrainedValue::Unresolved(ref value) => write!(f, "{}", value),