Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Draft] Network retriever module #3374

Merged
merged 25 commits into from
Dec 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
1b9ac65
mess
evan-schott Oct 19, 2023
8b28c16
Add retriever module
evan-schott Nov 3, 2023
551eb1e
Examples
evan-schott Nov 3, 2023
1aac5ef
Retriever module
evan-schott Nov 3, 2023
26ff2b5
Change disassembler structure
evan-schott Nov 3, 2023
da1419c
Compiler::new() changes
evan-schott Nov 3, 2023
c7d3cf9
Test CLI build command
evan-schott Nov 3, 2023
650d47f
Integrate network retrieval to build system
evan-schott Nov 3, 2023
c44949c
Add new errors
evan-schott Nov 3, 2023
cd3ae36
Clippy fix
evan-schott Nov 3, 2023
3ff41db
Default trait for stubs
evan-schott Nov 3, 2023
184c2f5
Print imports in post order
evan-schott Nov 3, 2023
d5cbd8e
Modify compiler struct
evan-schott Nov 3, 2023
bb960bf
Merge dependencies stated in `program.json` w/ dependencies stated in…
evan-schott Nov 3, 2023
3695ac6
clippy
evan-schott Nov 3, 2023
a55e5e4
post rebase patches
evan-schott Nov 4, 2023
babac66
Working example in . Run test in and to see it in action
evan-schott Nov 4, 2023
931698f
Working example in `utils/tmp/nested`. Run test in `cli.rs` and `retr…
evan-schott Nov 4, 2023
3564389
add proper error checking
evan-schott Nov 8, 2023
b7e6bca
versioning update
evan-schott Dec 2, 2023
51dd617
return stubs in post order from retrieval module
evan-schott Dec 2, 2023
4b3b198
reorganization of errors
evan-schott Dec 2, 2023
94b3290
remove leftover traces of previous import system
evan-schott Dec 2, 2023
20a4278
allow functions to have empty blocks
evan-schott Dec 2, 2023
db20544
merge `program.json` and `.leo` dependencies in `compiler.rs`
evan-schott Dec 2, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 23 additions & 21 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 6 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ members = [
"errors",
"leo/package",
"tests/test-framework",
"utils/disassembler"
"utils/disassembler",
"utils/retriever"
]

[workspace.dependencies.snarkvm]
Expand Down Expand Up @@ -84,6 +85,10 @@ version = "=1.10.0"
path = "./compiler/span"
version = "=1.10.0"

[dependencies.retriever]
path = "./utils/retriever"
version = "1.10.0"

[dependencies.backtrace]
version = "0.3.68"

Expand Down Expand Up @@ -123,10 +128,6 @@ default-features = false
[dependencies.rand_core]
version = "0.6.4"

[dependencies.reqwest]
version = "0.11.22"
features = [ "blocking", "json", "multipart" ]

[dependencies.self_update]
version = "0.39.0"
features = [ "archive-zip" ]
Expand Down
20 changes: 19 additions & 1 deletion compiler/ast/src/stub/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub use finalize_stub::*;
pub mod function_stub;
pub use function_stub::*;

use crate::{ConstDeclaration, Mapping, ProgramId, Struct};
use crate::{ConstDeclaration, Identifier, Mapping, NodeID, ProgramId, Struct};
use leo_span::{Span, Symbol};
use serde::{Deserialize, Serialize};
use std::fmt;
Expand All @@ -45,6 +45,24 @@ pub struct Stub {
pub span: Span,
}

impl Default for Stub {
/// Constructs an empty program stub
fn default() -> Self {
Self {
imports: Vec::new(),
stub_id: ProgramId {
name: Identifier::new(Symbol::intern(""), NodeID::default()),
network: Identifier::new(Symbol::intern(""), NodeID::default()),
},
consts: Vec::new(),
structs: Vec::new(),
mappings: Vec::new(),
functions: Vec::new(),
span: Span::default(),
}
}
}

impl fmt::Display for Stub {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "stub {} {{", self.stub_id)?;
Expand Down
6 changes: 5 additions & 1 deletion compiler/compiler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ version = "=1.10.0"
[dependencies.sha2]
version = "0.10"

[dependencies.indexmap]
version = "1.9"
features = []

[dev-dependencies.leo-test-framework]
path = "../../tests/test-framework"

Expand Down Expand Up @@ -72,4 +76,4 @@ version = "3.8"

[features]
default = [ ]
ci_skip = [ "leo-ast/ci_skip" ]
ci_skip = [ "leo-ast/ci_skip" ]
48 changes: 46 additions & 2 deletions compiler/compiler/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,17 @@
//!
//! The [`Compiler`] type compiles Leo programs into R1CS circuits.
pub use leo_ast::{Ast, InputAst};
use leo_ast::{NodeBuilder, Program};
use leo_ast::{NodeBuilder, Program, Stub};
use leo_errors::{emitter::Handler, CompilerError, Result};
pub use leo_passes::SymbolTable;
use leo_passes::*;
use leo_span::{source_map::FileName, symbol::with_session_globals};
use leo_span::{source_map::FileName, symbol::with_session_globals, Symbol};

use sha2::{Digest, Sha256};
use std::{fs, path::PathBuf};

use crate::CompilerOptions;
use indexmap::{IndexMap, IndexSet};

/// The primary entry point of the Leo compiler.
#[derive(Clone)]
Expand All @@ -54,6 +55,8 @@ pub struct Compiler<'a> {
assigner: Assigner,
/// The type table.
type_table: TypeTable,
/// The stubs for imported programs. Produced by `Retriever` module.
import_stubs: IndexMap<Symbol, Stub>,
}

impl<'a> Compiler<'a> {
Expand All @@ -65,6 +68,7 @@ impl<'a> Compiler<'a> {
main_file_path: PathBuf,
output_directory: PathBuf,
compiler_options: Option<CompilerOptions>,
import_stubs: IndexMap<Symbol, Stub>,
) -> Self {
let node_builder = NodeBuilder::default();
let assigner = Assigner::default();
Expand All @@ -80,6 +84,7 @@ impl<'a> Compiler<'a> {
compiler_options: compiler_options.unwrap_or_default(),
node_builder,
assigner,
import_stubs,
type_table,
}
}
Expand Down Expand Up @@ -324,6 +329,8 @@ impl<'a> Compiler<'a> {
pub fn compile(&mut self) -> Result<(SymbolTable, String)> {
// Parse the program.
self.parse_program()?;
// Copy the dependencies specified in `program.json` into the AST.
self.add_import_stubs()?;
// Run the intermediate compiler stages.
let (symbol_table, struct_graph, call_graph) = self.compiler_stages()?;
// Run code generation.
Expand Down Expand Up @@ -361,4 +368,41 @@ impl<'a> Compiler<'a> {
}
Ok(())
}

/// Merges the dependencies defined in `program.json` with the dependencies imported in `.leo` file
fn add_import_stubs(&mut self) -> Result<()> {
// Create a list of both the explicit dependencies specified in the `.leo` file, as well as the implicit ones derived from those dependencies.
let (mut unexplored, mut explored): (IndexSet<Symbol>, IndexSet<Symbol>) =
(self.ast.ast.imports.keys().cloned().collect(), IndexSet::new());
while !unexplored.is_empty() {
let mut current_dependencies: IndexSet<Symbol> = IndexSet::new();
for program_name in unexplored.iter() {
if let Some(stub) = self.import_stubs.get(program_name) {
// Add the program to the explored set
explored.insert(*program_name);
for dependency in stub.imports.iter() {
// If dependency is already explored then don't need to re-explore it
if explored.insert(dependency.name.name) {
current_dependencies.insert(dependency.name.name);
}
}
} else {
return Err(CompilerError::imported_program_not_found(
self.program_name.clone(),
*program_name,
self.ast.ast.imports[program_name].1,
)
.into());
}
}

// Create next batch to explore
unexplored = current_dependencies;
}

// Combine the dependencies from `program.json` and `.leo` file while preserving the post-order
self.ast.ast.stubs =
self.import_stubs.clone().into_iter().filter(|(program_name, _)| explored.contains(program_name)).collect();
Ok(())
}
}
11 changes: 10 additions & 1 deletion compiler/compiler/tests/utilities/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use leo_test_framework::{test::TestConfig, Test};

use snarkvm::prelude::*;

use indexmap::IndexMap;
use leo_ast::ProgramVisitor;
use snarkvm::{file::Manifest, package::Package};
use std::{
Expand Down Expand Up @@ -142,7 +143,15 @@ pub fn new_compiler(
let output_dir = PathBuf::from("/tmp/output/");
fs::create_dir_all(output_dir.clone()).unwrap();

Compiler::new(String::from("test"), String::from("aleo"), handler, main_file_path, output_dir, compiler_options)
Compiler::new(
String::from("test"),
String::from("aleo"),
handler,
main_file_path,
output_dir,
compiler_options,
IndexMap::new(),
)
}

pub fn parse_program<'a>(
Expand Down
7 changes: 1 addition & 6 deletions compiler/parser/src/parser/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ impl ParserContext<'_> {
};

// Parse the function body. Allow empty blocks. `fn foo(a:u8);`
let (has_empty_block, block) = match &self.token.token {
let (_has_empty_block, block) = match &self.token.token {
Token::LeftCurly => (false, self.parse_block()?),
Token::Semicolon => {
let semicolon = self.expect(&Token::Semicolon)?;
Expand All @@ -425,11 +425,6 @@ impl ParserContext<'_> {
let finalize = match self.eat(&Token::Finalize) {
false => None,
true => {
// Make sure has function body. Don't want `fn foo(); finalize foo { ... }` to be valid parsing.
if has_empty_block {
return Err(ParserError::empty_function_cannot_have_finalize(self.token.span).into());
}

// Get starting span.
let start = self.prev_token.span;

Expand Down
31 changes: 5 additions & 26 deletions compiler/passes/src/code_generation/visit_program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

use crate::CodeGenerator;

use leo_ast::{functions, Function, Mapping, Mode, Program, ProgramScope, Struct, Stub, Type, Variant};
use leo_ast::{functions, Function, Mapping, Mode, Program, ProgramScope, Struct, Type, Variant};

use indexmap::IndexMap;
use itertools::Itertools;
Expand All @@ -28,22 +28,10 @@ impl<'a> CodeGenerator<'a> {
// Accumulate instructions into a program string.
let mut program_string = String::new();

if !input.imports.is_empty() {
// Visit each import statement and produce a Aleo import instruction.
program_string.push_str(
&input
.imports
.iter()
.map(|(identifier, (imported_program, _))| self.visit_import(identifier, imported_program))
.join("\n"),
);

// Newline separator.
program_string.push('\n');
}

// Import stub programs
program_string.push_str(&input.stubs.values().map(|stub| self.visit_stub(stub)).join("\n"));
// Print out the dependencies of the program. Already arranged in post order by Retriever module.
input.stubs.iter().for_each(|(program_name, _)| {
program_string.push_str(&format!("import {}.aleo;\n", program_name));
});

// Retrieve the program scope.
// Note that type checking guarantees that there is exactly one program scope.
Expand Down Expand Up @@ -112,15 +100,6 @@ impl<'a> CodeGenerator<'a> {
program_string
}

fn visit_stub(&mut self, input: &'a Stub) -> String {
format!("import {}.aleo;", input.stub_id.name)
}

fn visit_import(&mut self, import_name: &'a Symbol, _import_program: &'a Program) -> String {
// Generate string for import statement.
format!("import {import_name}.aleo;")
}

fn visit_struct_or_record(&mut self, struct_: &'a Struct) -> String {
if struct_.is_record { self.visit_record(struct_) } else { self.visit_struct(struct_) }
}
Expand Down
Loading
Loading