Merge pull request #622 from AleoHQ/refactor/compiler

Adds ASG struct, updates ASG to support debug
This commit is contained in:
Collin Chin 2021-02-04 22:52:40 -08:00 committed by GitHub
commit a239e17bb6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
51 changed files with 225 additions and 205 deletions

View File

@ -26,6 +26,7 @@ path = "leo/main.rs"
[workspace]
members = [
"asg",
"ast",
"compiler",
"gadgets",
@ -34,8 +35,7 @@ members = [
"input",
"linter",
"package",
"state",
"asg"
"state"
]
[dependencies.leo-ast]

View File

@ -22,6 +22,7 @@ use std::{
sync::{Arc, Weak},
};
#[derive(Debug)]
pub struct ArrayAccessExpression {
pub parent: RefCell<Option<Weak<Expression>>>,
pub span: Option<Span>,

View File

@ -21,6 +21,7 @@ use std::{
sync::{Arc, Weak},
};
#[derive(Debug)]
pub struct ArrayInitExpression {
pub parent: RefCell<Option<Weak<Expression>>>,
pub span: Option<Span>,

View File

@ -22,6 +22,7 @@ use std::{
sync::{Arc, Weak},
};
#[derive(Debug)]
pub struct ArrayInlineExpression {
pub parent: RefCell<Option<Weak<Expression>>>,
pub span: Option<Span>,

View File

@ -22,6 +22,7 @@ use std::{
sync::{Arc, Weak},
};
#[derive(Debug)]
pub struct ArrayRangeAccessExpression {
pub parent: RefCell<Option<Weak<Expression>>>,
pub span: Option<Span>,

View File

@ -22,6 +22,7 @@ use std::{
sync::{Arc, Weak},
};
#[derive(Debug)]
pub struct BinaryExpression {
pub parent: RefCell<Option<Weak<Expression>>>,
pub span: Option<Span>,

View File

@ -36,6 +36,7 @@ use std::{
sync::{Arc, Weak},
};
#[derive(Debug)]
pub struct CallExpression {
pub parent: RefCell<Option<Weak<Expression>>>,
pub span: Option<Span>,

View File

@ -36,6 +36,7 @@ use std::{
sync::{Arc, Weak},
};
#[derive(Debug)]
pub struct CircuitAccessExpression {
pub parent: RefCell<Option<Weak<Expression>>>,
pub span: Option<Span>,

View File

@ -36,6 +36,7 @@ use std::{
sync::{Arc, Weak},
};
#[derive(Debug)]
pub struct CircuitInitExpression {
pub parent: RefCell<Option<Weak<Expression>>>,
pub span: Option<Span>,

View File

@ -34,6 +34,7 @@ use std::{
sync::{Arc, Weak},
};
#[derive(Debug)]
pub struct Constant {
pub parent: RefCell<Option<Weak<Expression>>>,
pub span: Option<Span>,

View File

@ -66,6 +66,7 @@ use crate::{AsgConvertError, ConstValue, FromAst, Node, PartialType, Scope, Span
use std::sync::{Arc, Weak};
#[derive(Debug)]
pub enum Expression {
VariableRef(VariableRef),
Constant(Constant),

View File

@ -21,6 +21,7 @@ use std::{
sync::{Arc, Weak},
};
#[derive(Debug)]
pub struct TernaryExpression {
pub parent: RefCell<Option<Weak<Expression>>>,
pub span: Option<Span>,

View File

@ -21,6 +21,7 @@ use std::{
sync::{Arc, Weak},
};
#[derive(Debug)]
pub struct TupleAccessExpression {
pub parent: RefCell<Option<Weak<Expression>>>,
pub span: Option<Span>,

View File

@ -21,6 +21,7 @@ use std::{
sync::{Arc, Weak},
};
#[derive(Debug)]
pub struct TupleInitExpression {
pub parent: RefCell<Option<Weak<Expression>>>,
pub span: Option<Span>,

View File

@ -22,6 +22,7 @@ use std::{
sync::{Arc, Weak},
};
#[derive(Debug)]
pub struct UnaryExpression {
pub parent: RefCell<Option<Weak<Expression>>>,
pub span: Option<Span>,

View File

@ -37,6 +37,7 @@ use std::{
sync::{Arc, Weak},
};
#[derive(Debug)]
pub struct VariableRef {
pub parent: RefCell<Option<Weak<Expression>>>,
pub span: Option<Span>,

View File

@ -23,7 +23,7 @@ use std::{
};
/// Stores program input values as asg nodes.
#[derive(Clone)]
#[derive(Debug, Clone)]
pub struct Input {
pub registers: Arc<CircuitBody>,
pub state: Arc<CircuitBody>,

View File

@ -67,9 +67,9 @@ pub use type_::*;
pub mod variable;
pub use variable::*;
pub use leo_ast::{Identifier, Span};
pub use leo_ast::{Ast, Identifier, Span};
use std::path::Path;
use std::{cell::RefCell, path::Path, sync::Arc};
/// The abstract semantic graph (ASG) for a Leo program.
///
@ -77,42 +77,41 @@ use std::path::Path;
/// These data types form a graph that begins from a [`Program`] type node.
///
/// A new [`Asg`] can be created from an [`Ast`] generated in the `ast` module.
// #[derive(Debug, Eq, PartialEq)]
// pub struct Asg {
// asg: InnerProgram,
// }
//
// impl Asg {
// /// Creates a new asg from a given ast tree and import resolver.
// pub fn new<T: ImportResolver + 'static>(
// content: leo_ast::Program,
// resolver: &mut T,
// ) -> Result<Program, AsgConvertError> {
// InnerProgram::new(&content, resolver)
// }
//
// /// Returns a reference to the inner program ast representation.
// pub fn into_repr(self) -> Program {
// self.asg
// }
// }
#[derive(Debug, Clone)]
pub struct Asg {
asg: Arc<RefCell<InternalProgram>>,
}
pub fn load_ast<T: AsRef<Path>, Y: AsRef<str>>(path: T, content: Y) -> Result<leo_ast::Program, AsgConvertError> {
impl Asg {
/// Creates a new ASG from a given AST and import resolver.
pub fn new<T: ImportResolver + 'static>(ast: &Ast, resolver: &mut T) -> Result<Self, AsgConvertError> {
Ok(Self {
asg: InternalProgram::new(&ast.as_repr(), resolver)?,
})
}
/// Returns the internal program ASG representation.
pub fn as_repr(&self) -> Arc<RefCell<InternalProgram>> {
self.asg.clone()
}
// /// Serializes the ast into a JSON string.
// pub fn to_json_string(&self) -> Result<String, serde_json::Error> {
// serde_json::to_string_pretty(&self.asg)
// }
//
// /// Deserializes the JSON string into a ast.
// pub fn from_json_string(json: &str) -> Result<Self, serde_json::Error> {
// let ast: Program = serde_json::from_str(json)?;
// Ok(Self { ast })
// }
}
// TODO (howardwu): Remove this.
pub fn load_asg<T: ImportResolver + 'static>(content: &str, resolver: &mut T) -> Result<Program, AsgConvertError> {
// Parses the Leo file and constructs a grammar ast.
let ast = leo_grammar::Grammar::new(path.as_ref(), content.as_ref())
let ast = leo_grammar::Grammar::new(&Path::new("input.leo"), content)
.map_err(|e| AsgConvertError::InternalError(format!("ast: {:?}", e)))?;
// Parses the pest ast and constructs a Leo ast.
Ok(leo_ast::Ast::new("load_ast", &ast)?.into_repr())
}
pub fn load_asg_from_ast<T: ImportResolver + 'static>(
content: leo_ast::Program,
resolver: &mut T,
) -> Result<Program, AsgConvertError> {
InnerProgram::new(&content, resolver)
}
pub fn load_asg<T: ImportResolver + 'static>(content: &str, resolver: &mut T) -> Result<Program, AsgConvertError> {
InnerProgram::new(&load_ast("input.leo", content)?, resolver)
InternalProgram::new(leo_ast::Ast::new("load_ast", &ast)?.as_repr(), resolver)
}

View File

@ -14,12 +14,12 @@
// 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/>.
//todo: we should merge this with core
// TODO (protryon): We should merge this with core
use crate::{AsgConvertError, Program};
// todo: make asg deep copy so we can cache resolved core modules
// todo: figure out how to do headers without bogus returns
// TODO (protryon): Make asg deep copy so we can cache resolved core modules
// TODO (protryon): Figure out how to do headers without bogus returns
pub fn resolve_core_module(module: &str) -> Result<Option<Program>, AsgConvertError> {
match module {

View File

@ -23,16 +23,19 @@ use std::{
};
use uuid::Uuid;
#[derive(Debug)]
pub enum CircuitMemberBody {
Variable(Type),
Function(Arc<FunctionBody>),
}
#[derive(Debug)]
pub enum CircuitMember {
Variable(WeakType),
Function(Arc<Function>),
}
#[derive(Debug)]
pub struct Circuit {
pub id: Uuid,
pub name: RefCell<Identifier>,
@ -51,6 +54,7 @@ impl PartialEq for Circuit {
}
impl Eq for Circuit {}
#[derive(Debug)]
pub struct CircuitBody {
pub scope: Scope,
pub span: Option<Span>,

View File

@ -38,13 +38,14 @@ use std::{
};
use uuid::Uuid;
#[derive(PartialEq)]
#[derive(Debug, PartialEq)]
pub enum FunctionQualifier {
SelfRef,
MutSelfRef,
Static,
}
#[derive(Debug)]
pub struct Function {
pub id: Uuid,
pub name: RefCell<Identifier>,
@ -66,6 +67,7 @@ impl PartialEq for Function {
}
impl Eq for Function {}
#[derive(Debug)]
pub struct FunctionBody {
pub span: Option<Span>,
pub function: Arc<Function>,

View File

@ -32,8 +32,8 @@ use std::{cell::RefCell, sync::Arc};
use uuid::Uuid;
/// Stores the Leo program abstract semantic graph (ASG).
#[derive(Clone)]
pub struct InnerProgram {
#[derive(Debug, Clone)]
pub struct InternalProgram {
/// The unique id of the program.
pub id: Uuid,
@ -57,7 +57,7 @@ pub struct InnerProgram {
pub scope: Scope,
}
pub type Program = Arc<RefCell<InnerProgram>>;
pub type Program = Arc<RefCell<InternalProgram>>;
/// Enumerates what names are imported from a package.
enum ImportSymbol {
@ -110,22 +110,22 @@ fn resolve_import_package_access(
}
}
impl InnerProgram {
/// Returns a new Leo program asg from the given Leo program ast and imports.
impl InternalProgram {
/// Returns a new Leo program ASG from the given Leo program AST and its imports.
///
/// stages:
/// Stages:
/// 1. resolve imports into super scope
/// 2. finalize declared types
/// 3. finalize declared functions
/// 4. resolve all asg nodes
///
pub fn new<T: ImportResolver + 'static>(
value: &leo_ast::Program,
program: &leo_ast::Program,
import_resolver: &mut T,
) -> Result<Program, AsgConvertError> {
// Recursively extract imported symbols.
let mut imported_symbols: Vec<(Vec<String>, ImportSymbol, Span)> = vec![];
for import in value.imports.iter() {
for import in program.imports.iter() {
resolve_import_package(&mut imported_symbols, vec![], &import.package);
}
@ -213,7 +213,7 @@ impl InnerProgram {
// Prepare header-like scope entries.
let mut proto_circuits = IndexMap::new();
for (name, circuit) in value.circuits.iter() {
for (name, circuit) in program.circuits.iter() {
assert_eq!(name.name, circuit.circuit_name.name);
let asg_circuit = Circuit::init(circuit);
@ -234,7 +234,7 @@ impl InnerProgram {
function: None,
}));
for (name, circuit) in value.circuits.iter() {
for (name, circuit) in program.circuits.iter() {
assert_eq!(name.name, circuit.circuit_name.name);
let asg_circuit = proto_circuits.get(&name.name).unwrap();
@ -242,7 +242,7 @@ impl InnerProgram {
}
let mut proto_test_functions = IndexMap::new();
for (name, test_function) in value.tests.iter() {
for (name, test_function) in program.tests.iter() {
assert_eq!(name.name, test_function.function.identifier.name);
let function = Arc::new(Function::from_ast(&scope, &test_function.function)?);
@ -250,7 +250,7 @@ impl InnerProgram {
}
let mut proto_functions = IndexMap::new();
for (name, function) in value.functions.iter() {
for (name, function) in program.functions.iter() {
assert_eq!(name.name, function.identifier.name);
let asg_function = Arc::new(Function::from_ast(&scope, function)?);
@ -263,7 +263,7 @@ impl InnerProgram {
// Load concrete definitions.
let mut test_functions = IndexMap::new();
for (name, test_function) in value.tests.iter() {
for (name, test_function) in program.tests.iter() {
assert_eq!(name.name, test_function.function.identifier.name);
let function = proto_test_functions.get(&name.name).unwrap();
@ -278,7 +278,7 @@ impl InnerProgram {
}
let mut functions = IndexMap::new();
for (name, function) in value.functions.iter() {
for (name, function) in program.functions.iter() {
assert_eq!(name.name, function.identifier.name);
let asg_function = proto_functions.get(&name.name).unwrap();
@ -289,7 +289,7 @@ impl InnerProgram {
}
let mut circuits = IndexMap::new();
for (name, circuit) in value.circuits.iter() {
for (name, circuit) in program.circuits.iter() {
assert_eq!(name.name, circuit.circuit_name.name);
let asg_circuit = proto_circuits.get(&name.name).unwrap();
let body = Arc::new(CircuitBody::from_ast(&scope, circuit, asg_circuit.clone())?);
@ -298,9 +298,9 @@ impl InnerProgram {
circuits.insert(name.name.clone(), body);
}
Ok(Arc::new(RefCell::new(InnerProgram {
Ok(Arc::new(RefCell::new(InternalProgram {
id: Uuid::new_v4(),
name: value.name.clone(),
name: program.name.clone(),
test_functions,
functions,
circuits,
@ -332,7 +332,7 @@ impl Iterator for InternalIdentifierGenerator {
Some(out)
}
}
/// Returns an ast from the given asg program.
/// Returns an AST from the given ASG program.
pub fn reform_ast(program: &Program) -> leo_ast::Program {
let mut all_programs: IndexMap<String, Program> = IndexMap::new();
let mut program_stack = program.borrow().imported_modules.clone();
@ -417,7 +417,7 @@ pub fn reform_ast(program: &Program) -> leo_ast::Program {
}
}
impl Into<leo_ast::Program> for &InnerProgram {
impl Into<leo_ast::Program> for &InternalProgram {
fn into(self) -> leo_ast::Program {
leo_ast::Program {
name: self.name.clone(),

View File

@ -157,7 +157,7 @@ pub trait MonoidalReducerProgram<T: Monoid>: MonoidalReducerStatement<T> {
fn reduce_program(
&mut self,
input: &InnerProgram,
input: &InternalProgram,
imported_modules: Vec<T>,
test_functions: Vec<T>,
functions: Vec<T>,

View File

@ -21,6 +21,7 @@ use std::{cell::RefCell, sync::Arc};
use uuid::Uuid;
/// An abstract data type that track the current bindings for variables, functions, and circuits.
#[derive(Debug)]
pub struct InnerScope {
/// The unique id of the scope.
pub id: Uuid,

View File

@ -37,6 +37,7 @@ use leo_ast::AssigneeAccess as AstAssigneeAccess;
use std::sync::{Arc, Weak};
#[derive(Debug)]
pub enum AssignAccess {
ArrayRange(Option<Arc<Expression>>, Option<Arc<Expression>>),
ArrayIndex(Arc<Expression>),
@ -44,6 +45,7 @@ pub enum AssignAccess {
Member(Identifier),
}
#[derive(Debug)]
pub struct AssignStatement {
pub parent: Option<Weak<Statement>>,
pub span: Option<Span>,

View File

@ -18,6 +18,7 @@ use crate::{AsgConvertError, FromAst, InnerScope, Node, PartialType, Scope, Span
use std::sync::{Arc, Weak};
#[derive(Debug)]
pub struct BlockStatement {
pub parent: Option<Weak<Statement>>,
pub span: Option<Span>,

View File

@ -18,6 +18,7 @@ use crate::{AsgConvertError, BlockStatement, Expression, FromAst, Node, PartialT
use std::sync::{Arc, Weak};
#[derive(Debug)]
pub struct ConditionalStatement {
pub parent: Option<Weak<Statement>>,
pub span: Option<Span>,

View File

@ -19,7 +19,8 @@ use leo_ast::ConsoleFunction as AstConsoleFunction;
use std::sync::{Arc, Weak};
//todo: refactor to not require/depend on span
// TODO (protryon): Refactor to not require/depend on span
#[derive(Debug)]
pub struct FormattedString {
pub string: String,
pub containers: Vec<Span>,
@ -27,6 +28,7 @@ pub struct FormattedString {
pub span: Span,
}
#[derive(Debug)]
pub enum ConsoleFunction {
Assert(Arc<Expression>),
Debug(FormattedString),
@ -34,6 +36,7 @@ pub enum ConsoleFunction {
Log(FormattedString),
}
#[derive(Debug)]
pub struct ConsoleStatement {
pub parent: Option<Weak<Statement>>,
pub span: Option<Span>,

View File

@ -34,6 +34,7 @@ use std::{
sync::{Arc, Weak},
};
#[derive(Debug)]
pub struct DefinitionStatement {
pub parent: Option<Weak<Statement>>,
pub span: Option<Span>,

View File

@ -18,6 +18,7 @@ use crate::{AsgConvertError, Expression, FromAst, Node, PartialType, Scope, Span
use std::sync::{Arc, Weak};
#[derive(Debug)]
pub struct ExpressionStatement {
pub parent: Option<Weak<Statement>>,
pub span: Option<Span>,

View File

@ -35,6 +35,7 @@ use std::{
sync::{Arc, Weak},
};
#[derive(Debug)]
pub struct IterationStatement {
pub parent: Option<Weak<Statement>>,
pub span: Option<Span>,

View File

@ -46,6 +46,7 @@ use crate::{AsgConvertError, FromAst, Node, PartialType, Scope, Span};
use std::sync::Arc;
#[derive(Debug)]
pub enum Statement {
Return(ReturnStatement),
Definition(DefinitionStatement),

View File

@ -18,6 +18,7 @@ use crate::{AsgConvertError, Expression, FromAst, Node, PartialType, Scope, Span
use std::sync::{Arc, Weak};
#[derive(Debug)]
pub struct ReturnStatement {
pub parent: Option<Weak<Statement>>,
pub span: Option<Span>,

View File

@ -22,8 +22,8 @@ use std::{
sync::{Arc, Weak},
};
/// A type in an asg.
#[derive(Clone, PartialEq)]
/// A type in an ASG.
#[derive(Debug, Clone, PartialEq)]
pub enum Type {
// Data types
Address,
@ -38,13 +38,13 @@ pub enum Type {
Circuit(Arc<Circuit>),
}
#[derive(Clone)]
#[derive(Debug, Clone)]
pub enum WeakType {
Type(Type), // circuit not allowed
Circuit(Weak<Circuit>),
}
#[derive(Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq)]
pub enum PartialType {
Type(Type), // non-array or tuple
Integer(Option<IntegerType>, Option<IntegerType>), // specific, context-specific

View File

@ -24,7 +24,7 @@ use std::{
use uuid::Uuid;
/// Specifies how a program variable was declared.
#[derive(PartialEq)]
#[derive(Debug, PartialEq)]
pub enum VariableDeclaration {
Definition,
IterationDefinition,
@ -33,6 +33,7 @@ pub enum VariableDeclaration {
}
/// Stores information on a program variable.
#[derive(Debug)]
pub struct InnerVariable {
pub id: Uuid,
pub name: Identifier,

View File

@ -15,16 +15,28 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use leo_asg::*;
use leo_ast::Ast;
use leo_grammar::Grammar;
use std::path::Path;
mod fail;
mod pass;
fn load_asg(content: &str) -> Result<Program, AsgConvertError> {
leo_asg::load_asg(content, &mut NullImportResolver)
const TESTING_FILEPATH: &str = "input.leo";
const TESTING_PROGRAM_NAME: &str = "test_program";
fn load_asg(program_string: &str) -> Result<Program, AsgConvertError> {
load_asg_imports(program_string, &mut NullImportResolver)
}
fn load_asg_imports<T: ImportResolver + 'static>(content: &str, imports: &mut T) -> Result<Program, AsgConvertError> {
leo_asg::load_asg(content, imports)
fn load_asg_imports<T: ImportResolver + 'static>(
program_string: &str,
imports: &mut T,
) -> Result<Program, AsgConvertError> {
let grammar = Grammar::new(Path::new(&TESTING_FILEPATH), program_string)?;
let ast = Ast::new(TESTING_PROGRAM_NAME, &grammar)?;
InternalProgram::new(&ast.as_repr(), imports)
}
fn mocked_resolver() -> MockedImportResolver {

View File

@ -15,6 +15,10 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::load_asg;
use leo_ast::Ast;
use leo_grammar::Grammar;
use std::path::Path;
#[test]
fn test_basic() {
@ -73,14 +77,19 @@ fn test_imports() {
console.assert(foo() == 1u32);
}
"#;
let test_import_grammar = Grammar::new(Path::new("test-import.leo"), test_import).unwrap();
println!(
"{}",
serde_json::to_string(&crate::load_ast("test-import.leo", test_import).unwrap()).unwrap()
serde_json::to_string(Ast::new("test-import", &test_import_grammar).unwrap().as_repr()).unwrap()
);
let test_grammar = Grammar::new(Path::new("test.leo"), program_string).unwrap();
println!(
"{}",
serde_json::to_string(&crate::load_ast("test.leo", program_string).unwrap()).unwrap()
serde_json::to_string(Ast::new("test", &test_grammar).unwrap().as_repr()).unwrap()
);
let asg = crate::load_asg_imports(program_string, &mut imports).unwrap();
let reformed_ast = leo_asg::reform_ast(&asg);
println!("{}", serde_json::to_string(&reformed_ast).unwrap());

View File

@ -63,7 +63,7 @@ pub use node::*;
use leo_grammar::Grammar;
/// The abstract syntax tree (ast) for a Leo program.
/// The abstract syntax tree (AST) for a Leo program.
///
/// The [`Ast`] type represents a Leo program as a series of recursive data types.
/// These data types form a tree that begins from a [`Program`] type root.
@ -75,16 +75,16 @@ pub struct Ast {
}
impl Ast {
/// Creates a new ast from a given program name and grammar tree.
pub fn new<'ast>(program_name: &str, ast: &Grammar<'ast>) -> Result<Self, AstError> {
/// Creates a new AST from a given program name and grammar tree.
pub fn new<'ast>(program_name: &str, grammar: &Grammar<'ast>) -> Result<Self, AstError> {
Ok(Self {
ast: Program::from(program_name, ast.as_repr())?,
ast: Program::from(program_name, grammar.as_repr())?,
})
}
/// Returns a reference to the inner program ast representation.
pub fn into_repr(self) -> Program {
self.ast
/// Returns a reference to the inner program AST representation.
pub fn as_repr(&self) -> &Program {
&self.ast
}
/// Serializes the ast into a JSON string.

View File

@ -44,7 +44,7 @@ fn test_serialize() {
};
// Serializes the ast into JSON format.
let serialized_ast: Program = serde_json::from_value(serde_json::to_value(ast.into_repr()).unwrap()).unwrap();
let serialized_ast: Program = serde_json::from_value(serde_json::to_value(ast.as_repr()).unwrap()).unwrap();
// Load the expected ast.
let expected: Program = serde_json::from_str(include_str!("expected_leo_ast.json")).unwrap();

View File

@ -23,13 +23,13 @@ use crate::{
OutputBytes,
OutputFile,
};
use leo_asg::Asg;
use leo_ast::{Ast, Input, MainInput, Program};
use leo_grammar::Grammar;
use leo_input::LeoInputParser;
use leo_package::inputs::InputPairs;
use leo_state::verify_local_data_commitment;
use leo_asg::Program as AsgProgram;
use snarkvm_dpc::{base_dpc::instantiated::Components, SystemParameters};
use snarkvm_errors::gadgets::SynthesisError;
use snarkvm_models::{
@ -47,12 +47,12 @@ use std::{
/// Stores information to compile a Leo program.
#[derive(Clone)]
pub struct Compiler<F: Field + PrimeField, G: GroupType<F>> {
package_name: String,
program_name: String,
main_file_path: PathBuf,
output_directory: PathBuf,
program: Program,
program_input: Input,
asg: Option<AsgProgram>,
asg: Option<Asg>,
_engine: PhantomData<F>,
_group: PhantomData<G>,
}
@ -63,7 +63,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
///
pub fn new(package_name: String, main_file_path: PathBuf, output_directory: PathBuf) -> Self {
Self {
package_name: package_name.clone(),
program_name: package_name.clone(),
main_file_path,
output_directory,
program: Program::new(package_name),
@ -88,7 +88,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
) -> Result<Self, CompilerError> {
let mut compiler = Self::new(package_name, main_file_path, output_directory);
compiler.parse_and_check_program()?;
compiler.parse_program()?;
Ok(compiler)
}
@ -114,7 +114,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
compiler.parse_input(input_string, input_path, state_string, state_path)?;
compiler.parse_and_check_program()?;
compiler.parse_program()?;
Ok(compiler)
}
@ -156,51 +156,16 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
Ok(())
}
///
/// Runs program parser and type inference checker consecutively.
///
pub(crate) fn parse_and_check_program(&mut self) -> Result<(), CompilerError> {
self.parse_program()
}
///
/// Parses and stores the main program file, constructs a syntax tree, and generates a program.
///
/// Parses and stores all programs imported by the main program file.
///
pub(crate) fn parse_program(&mut self) -> Result<(), CompilerError> {
pub fn parse_program(&mut self) -> Result<(), CompilerError> {
// Load the program file.
let program_string = Grammar::load_file(&self.main_file_path)?;
// Use the parser to construct the pest abstract syntax tree (ast).
let pest_ast = Grammar::new(&self.main_file_path, &program_string).map_err(|mut e| {
e.set_path(&self.main_file_path);
e
})?;
// Construct the core ast from the pest ast.
let core_ast = Ast::new(&self.package_name, &pest_ast)?;
// Store the main program file.
self.program = core_ast.into_repr();
tracing::debug!("Program parsing complete\n{:#?}", self.program);
self.program_asg_generate()?;
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, &mut leo_imports::ImportParser::default())?;
tracing::debug!("ASG generation complete");
self.asg = Some(asg);
Ok(())
self.parse_program_from_string(&program_string)
}
///
@ -208,52 +173,56 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
/// file path.
///
pub fn parse_program_from_string(&mut self, program_string: &str) -> Result<(), CompilerError> {
// Use the given bytes to construct the abstract syntax tree.
let ast = Grammar::new(&self.main_file_path, &program_string).map_err(|mut e| {
// Use the parser to construct the pest abstract syntax tree (ast).
let grammar = Grammar::new(&self.main_file_path, &program_string).map_err(|mut e| {
e.set_path(&self.main_file_path);
e
})?;
// Derive the package name.
let package_name = &self.package_name;
// Construct the core ast from the pest ast.
let core_ast = Ast::new(package_name, &ast)?;
// Construct the AST from the grammar.
let core_ast = Ast::new(&self.program_name, &grammar)?;
// Store the main program file.
self.program = core_ast.into_repr();
self.program = core_ast.as_repr().clone();
tracing::debug!("Program parsing complete\n{:#?}", self.program);
self.program_asg_generate()?;
// Create a new symbol table from the program, imported_programs, and program_input.
let asg = Asg::new(&core_ast, &mut leo_imports::ImportParser::default())?;
tracing::debug!("ASG generation complete");
// Store the ASG.
self.asg = Some(asg);
Ok(())
}
///
/// Manually sets main function input.
/// Synthesizes the circuit with program input to verify correctness.
///
/// Used for testing only.
///
pub fn set_main_input(&mut self, input: MainInput) {
self.program_input.set_main_input(input);
pub fn compile_constraints<CS: ConstraintSystem<F>>(&self, cs: &mut CS) -> Result<OutputBytes, CompilerError> {
generate_constraints::<F, G, CS>(cs, &self.asg.as_ref().unwrap(), &self.program_input).map_err(|mut error| {
error.set_path(&self.main_file_path);
error
})
}
///
/// Verifies the input to the program.
/// Synthesizes the circuit for test functions with program input.
///
pub fn verify_local_data_commitment(
&self,
system_parameters: &SystemParameters<Components>,
) -> Result<bool, CompilerError> {
let result = verify_local_data_commitment(system_parameters, &self.program_input)?;
Ok(result)
pub fn compile_test_constraints(self, input_pairs: InputPairs) -> Result<(u32, u32), CompilerError> {
generate_test_constraints::<F, G>(
&self.asg.as_ref().unwrap(),
input_pairs,
&self.main_file_path,
&self.output_directory,
)
}
///
/// Returns a Sha256 checksum of the program file.
/// Returns a SHA256 checksum of the program file.
///
pub fn checksum(&self) -> Result<String, CompilerError> {
// Read in the main file as string
@ -268,43 +237,27 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
Ok(hex::encode(hash))
}
/// TODO (howardwu): Incorporate this for real program executions and intentionally-real
/// test executions. Exclude it for test executions on dummy data.
///
/// Synthesizes the circuit without program input to verify correctness.
/// Verifies the input to the program.
///
pub fn compile_constraints<CS: ConstraintSystem<F>>(self, cs: &mut CS) -> Result<OutputBytes, CompilerError> {
let path = self.main_file_path;
generate_constraints::<F, G, CS>(cs, self.asg.as_ref().unwrap(), &self.program_input).map_err(|mut error| {
error.set_path(&path);
error
})
}
///
/// Synthesizes the circuit for test functions with program input.
///
pub fn compile_test_constraints(self, input_pairs: InputPairs) -> Result<(u32, u32), CompilerError> {
generate_test_constraints::<F, G>(
self.asg.as_ref().unwrap(),
input_pairs,
&self.main_file_path,
&self.output_directory,
)
}
///
/// Calls the internal generate_constraints method with arguments.
///
pub fn generate_constraints_helper<CS: ConstraintSystem<F>>(
pub fn verify_local_data_commitment(
&self,
cs: &mut CS,
) -> Result<OutputBytes, CompilerError> {
let path = &self.main_file_path;
generate_constraints::<_, G, _>(cs, self.asg.as_ref().unwrap(), &self.program_input).map_err(|mut error| {
error.set_path(&path);
error
})
system_parameters: &SystemParameters<Components>,
) -> Result<bool, CompilerError> {
let result = verify_local_data_commitment(system_parameters, &self.program_input)?;
Ok(result)
}
///
/// Manually sets main function input.
///
/// Used for testing only.
///
pub fn set_main_input(&mut self, input: MainInput) {
self.program_input.set_main_input(input);
}
}
@ -314,8 +267,8 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstraintSynthesizer<F> for Compil
///
fn generate_constraints<CS: ConstraintSystem<F>>(&self, cs: &mut CS) -> Result<(), SynthesisError> {
let output_directory = self.output_directory.clone();
let package_name = self.package_name.clone();
let result = self.generate_constraints_helper(cs).map_err(|e| {
let package_name = self.program_name.clone();
let result = self.compile_constraints(cs).map_err(|e| {
tracing::error!("{}", e);
SynthesisError::Unsatisfiable
})?;

View File

@ -17,7 +17,7 @@
//! Generates R1CS constraints for a compiled Leo program.
use crate::{errors::CompilerError, ConstrainedProgram, GroupType, OutputBytes, OutputFile};
use leo_asg::Program;
use leo_asg::Asg;
use leo_ast::Input;
use leo_input::LeoInputParser;
use leo_package::inputs::InputPairs;
@ -30,9 +30,10 @@ use std::path::Path;
pub fn generate_constraints<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>>(
cs: &mut CS,
program: &Program,
asg: &Asg,
input: &Input,
) -> Result<OutputBytes, CompilerError> {
let program = asg.as_repr();
let mut resolved_program = ConstrainedProgram::<F, G>::new(program.clone());
let main = {
@ -50,11 +51,12 @@ pub fn generate_constraints<F: Field + PrimeField, G: GroupType<F>, CS: Constrai
}
pub fn generate_test_constraints<F: Field + PrimeField, G: GroupType<F>>(
program: &Program,
asg: &Asg,
input: InputPairs,
main_file_path: &Path,
output_directory: &Path,
) -> Result<(u32, u32), CompilerError> {
let program = asg.as_repr();
let mut resolved_program = ConstrainedProgram::<F, G>::new(program.clone());
let program_name = program.borrow().name.clone();

View File

@ -146,7 +146,7 @@ pub fn parse_program_with_input_and_state(
pub(crate) fn get_output(program: EdwardsTestCompiler) -> OutputBytes {
// synthesize the circuit on the test constraint system
let mut cs = TestConstraintSystem::<Fq>::new();
let output = program.generate_constraints_helper(&mut cs).unwrap();
let output = program.compile_constraints(&mut cs).unwrap();
// assert the constraint system is satisfied
assert!(cs.is_satisfied());
@ -164,7 +164,7 @@ pub(crate) fn assert_satisfied(program: EdwardsTestCompiler) {
pub(crate) fn expect_compiler_error(program: EdwardsTestCompiler) -> CompilerError {
let mut cs = TestConstraintSystem::<Fq>::new();
program.generate_constraints_helper(&mut cs).unwrap_err()
program.compile_constraints(&mut cs).unwrap_err()
}
pub(crate) fn expect_asg_error(error: CompilerError) {

View File

@ -22,8 +22,8 @@ name = "leo_grammar"
path = "src/main.rs"
[[bench]]
name = "ast"
path = "benches/ast.rs"
name = "grammar"
path = "benches/grammar.rs"
harness = false
[dependencies.from-pest]

View File

@ -2,7 +2,7 @@ circuit PedersenHash {
parameters: [group; 256],
// Instantiates a Pedersen hash circuit
static function new(parameters: [group; 256]) -> Self {
function new(self, parameters: [group; 256]) -> Self {
return Self { parameters: parameters }
}

View File

@ -44,8 +44,8 @@ use pest::{
#[grammar = "leo.pest"]
pub struct LanguageParser;
pub fn parse(input: &str) -> Result<Pairs<Rule>, Error<Rule>> {
LanguageParser::parse(Rule::file, input)
pub fn parse(program_string: &str) -> Result<Pairs<Rule>, Error<Rule>> {
LanguageParser::parse(Rule::file, program_string)
}
pub(crate) fn span_into_string(span: Span) -> String {

View File

@ -17,8 +17,8 @@
use crate::ast::Rule;
use pest_ast::FromPest;
use serde::Serialize;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[derive(Clone, Debug, FromPest, PartialEq, Serialize, Deserialize)]
#[pest_ast(rule(Rule::EOI))]
pub struct EOI;

View File

@ -53,19 +53,23 @@ pub(crate) use span::*;
use from_pest::FromPest;
use std::{fs, path::Path};
/// The pest abstract syntax tree (ast) for a Leo program.
///
/// The grammar of a Leo program, encoded as an abstract syntax tree (AST).
///
/// The [`Grammar`] type represents a Leo program as a series of recursive data types.
/// These data types form a tree that begins from a [`File`] type root.
///
/// A new [`Grammar`] type can be created from a `*.leo` file at a [`Path`].
/// A [`Grammar`] type can be used to create a new [`Ast`] type.
///
pub struct Grammar<'ast> {
ast: files::File<'ast>,
}
impl<'ast> Grammar<'ast> {
/// Creates a new abstract syntax tree given the file path.
///
/// Creates a new abstract syntax tree from a given program string, and optional file path.
///
pub fn new(file_path: &'ast Path, program_string: &'ast str) -> Result<Self, ParserError> {
// TODO (howardwu): Turn this check back on after fixing the testing module.
// assert_eq!(program_string, fs::read_to_string(file_path).map_err(|_| ParserError::FileReadError(file_path.clone()))?);
@ -83,17 +87,23 @@ impl<'ast> Grammar<'ast> {
// TODO (howardwu): Remove this in favor of a dedicated file loader to verify checksums
// and maintain a global cache of program strings during the compilation process.
///
/// Loads the Leo code as a string from the given file path.
///
pub fn load_file(file_path: &'ast Path) -> Result<String, ParserError> {
fs::read_to_string(file_path).map_err(|_| ParserError::FileReadError(file_path.to_owned()))
}
///
/// Returns a reference to the inner abstract syntax tree representation.
///
pub fn as_repr(&self) -> &files::File<'ast> {
&self.ast
}
///
/// Serializes the abstract syntax tree into a JSON string.
///
pub fn to_json_string(&self) -> Result<String, ParserError> {
Ok(serde_json::to_string_pretty(&self.ast)?)
}

View File

@ -15,11 +15,11 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use pest::Span;
use serde::Serialize;
use serde::{Deserialize, Serialize};
// Provide getters for every private field of the remote struct. The getter must
// return either `T` or `&T` where `T` is the type of the field.
#[derive(Serialize)]
#[derive(Serialize, Deserialize)]
#[serde(remote = "Span")]
pub(crate) struct SpanDef<'i> {
/// # Attention

View File

@ -34,7 +34,7 @@ impl ImportParser {
return self.parse_package(package.path(), remaining_segments, span);
}
let program = Self::parse_import_file(package, span)?;
let asg = leo_asg::InnerProgram::new(&program, self)?;
let asg = leo_asg::InternalProgram::new(&program, self)?;
Ok(asg)
}

View File

@ -31,18 +31,18 @@ use snarkvm_utilities::{bytes::ToBytes, to_bytes, FromBytes};
use std::convert::TryFrom;
/// Returns `true` if the path to the local data commitment leaf is a valid path in the record
/// commitment merkle tree.
/// commitment Merkle tree.
pub fn verify_local_data_commitment(
system_parameters: &SystemParameters<Components>,
ast_input: &AstInput,
) -> Result<bool, LocalDataVerificationError> {
// verify record commitment.
// Verify record commitment.
let typed_record = ast_input.get_record();
let dpc_record_values = verify_record_commitment(system_parameters, typed_record)?;
let record_commitment: Vec<u8> = dpc_record_values.commitment;
let record_serial_number: Vec<u8> = dpc_record_values.serial_number;
// parse typed state values.
// Parse typed state values.
let typed_state = ast_input.get_state();
let state_values = StateValues::try_from(typed_state)?;
let leaf_index: u32 = state_values.leaf_index;