Add complex finalization multi-program example; regen expectations

This commit is contained in:
Pranav Gaddamadugu 2024-03-27 20:15:24 -07:00
parent 4c750bc963
commit 058d3bf79a
15 changed files with 298 additions and 69 deletions

View File

@ -336,7 +336,7 @@ impl<'a> Compiler<'a> {
}
/// Merges the dependencies defined in `program.json` with the dependencies imported in `.leo` file
fn add_import_stubs(&mut self) -> Result<()> {
pub 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());

View File

@ -42,6 +42,7 @@ use snarkvm::console::prelude::*;
use indexmap::IndexMap;
use leo_span::Symbol;
use regex::Regex;
use serde_yaml::Value;
use snarkvm::{prelude::Process, synthesizer::program::ProgramCore};
use std::{fs, path::Path, rc::Rc};
@ -112,8 +113,12 @@ fn run_test(test: Test, handler: &Handler, buf: &BufferEmitter) -> Result<Value,
// Compile each program string separately.
for program_string in program_strings {
// Parse the program name from the program string.
let re = Regex::new(r"program\s+([^\s.]+)\.aleo").unwrap();
let program_name = re.captures(program_string).unwrap().get(1).unwrap().as_str();
// Parse the program.
let mut parsed = handler.extend_if_error(parse_program(
program_name.to_string(),
handler,
program_string,
cwd.clone(),
@ -139,10 +144,11 @@ fn run_test(test: Test, handler: &Handler, buf: &BufferEmitter) -> Result<Value,
// Hash the ast files.
let (initial_ast, unrolled_ast, ssa_ast, flattened_ast, destructured_ast, inlined_ast, dce_ast) =
hash_asts();
hash_asts(&program_name);
// Hash the symbol tables.
let (initial_symbol_table, type_checked_symbol_table, unrolled_symbol_table) = hash_symbol_tables();
let (initial_symbol_table, type_checked_symbol_table, unrolled_symbol_table) =
hash_symbol_tables(&program_name);
// Clean up the output directory.
if fs::read_dir("/tmp/output").is_ok() {

View File

@ -47,6 +47,7 @@ use disassembler::disassemble_from_str;
use indexmap::IndexMap;
use leo_errors::LeoError;
use leo_span::Symbol;
use regex::Regex;
use serde::{Deserialize, Serialize};
use serde_yaml::Value;
use snarkvm::{
@ -143,8 +144,13 @@ fn run_test(test: Test, handler: &Handler, buf: &BufferEmitter) -> Result<Value,
// Compile each program string separately.
for program_string in program_strings {
// Parse the program name from the program string.
let re = Regex::new(r"program\s+([^\s.]+)\.aleo").unwrap();
let program_name = re.captures(program_string).unwrap().get(1).unwrap().as_str();
// Parse the program.
let mut parsed = handler.extend_if_error(parse_program(
program_name.to_string(),
handler,
program_string,
cwd.clone(),
@ -178,10 +184,11 @@ fn run_test(test: Test, handler: &Handler, buf: &BufferEmitter) -> Result<Value,
// Hash the ast files.
let (initial_ast, unrolled_ast, ssa_ast, flattened_ast, destructured_ast, inlined_ast, dce_ast) =
hash_asts();
hash_asts(&program_name);
// Hash the symbol tables.
let (initial_symbol_table, type_checked_symbol_table, unrolled_symbol_table) = hash_symbol_tables();
let (initial_symbol_table, type_checked_symbol_table, unrolled_symbol_table) =
hash_symbol_tables(&program_name);
// Clean up the output directory.
if fs::read_dir("/tmp/output").is_ok() {
@ -243,7 +250,7 @@ fn run_test(test: Test, handler: &Handler, buf: &BufferEmitter) -> Result<Value,
// Initialize the statuses of execution.
let mut execution = None;
let mut verified = false;
let mut status = "None";
let mut status = "none";
// Execute the program, construct a block and add it to the ledger.
let result = std::panic::catch_unwind(AssertUnwindSafe(|| {
@ -264,10 +271,10 @@ fn run_test(test: Test, handler: &Handler, buf: &BufferEmitter) -> Result<Value,
})
.and_then(|block| {
status = match block.aborted_transaction_ids().is_empty() {
false => "Aborted",
false => "aborted",
true => match block.transactions().num_accepted() == 1 {
true => "Accepted",
false => "Rejected",
true => "accepted",
false => "rejected",
},
};
ledger.advance_to_next_block(&block)

View File

@ -49,22 +49,23 @@ pub type CurrentNetwork = Testnet3;
#[allow(unused)]
pub type CurrentAleo = snarkvm::circuit::AleoV0;
pub fn hash_asts() -> (String, String, String, String, String, String, String) {
let initial_ast = hash_file("/tmp/output/test.initial_ast.json");
let unrolled_ast = hash_file("/tmp/output/test.unrolled_ast.json");
let ssa_ast = hash_file("/tmp/output/test.ssa_ast.json");
let flattened_ast = hash_file("/tmp/output/test.flattened_ast.json");
let destructured_ast = hash_file("/tmp/output/test.destructured_ast.json");
let inlined_ast = hash_file("/tmp/output/test.inlined_ast.json");
let dce_ast = hash_file("/tmp/output/test.dce_ast.json");
pub fn hash_asts(program_name: &str) -> (String, String, String, String, String, String, String) {
let initial_ast = hash_file(&format!("/tmp/output/{program_name}.initial_ast.json"));
let unrolled_ast = hash_file(&format!("/tmp/output/{program_name}.unrolled_ast.json"));
let ssa_ast = hash_file(&format!("/tmp/output/{program_name}.ssa_ast.json"));
let flattened_ast = hash_file(&format!("/tmp/output/{program_name}.flattened_ast.json"));
let destructured_ast = hash_file(&format!("/tmp/output/{program_name}.destructured_ast.json"));
let inlined_ast = hash_file(&format!("/tmp/output/{program_name}.inlined_ast.json"));
let dce_ast = hash_file(&format!("/tmp/output/{program_name}.dce_ast.json"));
(initial_ast, unrolled_ast, ssa_ast, flattened_ast, destructured_ast, inlined_ast, dce_ast)
}
pub fn hash_symbol_tables() -> (String, String, String) {
let initial_symbol_table = hash_file("/tmp/output/test.initial_symbol_table.json");
let type_checked_symbol_table = hash_file("/tmp/output/test.type_checked_symbol_table.json");
let unrolled_symbol_table = hash_file("/tmp/output/test.unrolled_symbol_table.json");
pub fn hash_symbol_tables(program_name: &str) -> (String, String, String) {
let initial_symbol_table = hash_file(&format!("/tmp/output/{program_name}.initial_symbol_table.json"));
let type_checked_symbol_table = hash_file(&format!("/tmp/output/{program_name}.type_checked_symbol_table.json"));
let unrolled_symbol_table = hash_file(&format!("/tmp/output/{program_name}.unrolled_symbol_table.json"));
(initial_symbol_table, type_checked_symbol_table, unrolled_symbol_table)
}
@ -144,6 +145,7 @@ pub fn setup_build_directory(
}
pub fn new_compiler(
program_name: String,
handler: &Handler,
main_file_path: PathBuf,
compiler_options: Option<CompilerOptions>,
@ -153,7 +155,7 @@ pub fn new_compiler(
fs::create_dir_all(output_dir.clone()).unwrap();
Compiler::new(
String::from("test"),
program_name,
String::from("aleo"),
handler,
main_file_path,
@ -164,14 +166,20 @@ pub fn new_compiler(
}
pub fn parse_program<'a>(
program_name: String,
handler: &'a Handler,
program_string: &str,
cwd: Option<PathBuf>,
compiler_options: Option<CompilerOptions>,
import_stubs: IndexMap<Symbol, Stub>,
) -> Result<Compiler<'a>, LeoError> {
let mut compiler =
new_compiler(handler, cwd.clone().unwrap_or_else(|| "compiler-test".into()), compiler_options, import_stubs);
let mut compiler = new_compiler(
program_name,
handler,
cwd.clone().unwrap_or_else(|| "compiler-test".into()),
compiler_options,
import_stubs,
);
let name = cwd.map_or_else(|| FileName::Custom("compiler-test".into()), FileName::Real);
compiler.parse_program_from_string(program_string, name)?;
@ -242,6 +250,8 @@ pub fn temp_dir() -> PathBuf {
}
pub fn compile_and_process<'a>(parsed: &'a mut Compiler<'a>) -> Result<String, LeoError> {
parsed.add_import_stubs()?;
let st = parsed.symbol_table_pass()?;
CheckUniqueNodeIds::new().visit_program(&parsed.ast.ast);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,130 @@
/*
namespace: Execute
expectation: Pass
cases:
- program: four_program.aleo
function: a
input: []
*/
// This test checks that the finalization order is correct.
// The functions are invoked in the following order:
// "four::a"
// --> "two::b"
// --> "zero::c"
// --> "one::d"
// --> "three::e"
// --> "two::b"
// --> "zero::c"
// --> "one::d"
// --> "one::d"
// --> "zero::c"
// The future (call graph) produced by the top-level finalize should reflect this structure.
program zero_program.aleo {
mapping counts: address => u64;
transition c() {
return then finalize(self.signer);
}
finalize c(addr: address) {
let count: u64 = counts.get_or_use(addr, 0u64);
counts.set(addr, count + 1u64);
}
}
// --- Next Program --- //
program one_program.aleo {
mapping counts: address => u64;
transition d() {
return then finalize(self.signer);
}
finalize d(addr: address) {
let count: u64 = counts.get_or_use(addr, 0u64);
counts.set(addr, count + 1u64);
}
}
// --- Next Program --- //
import zero_program.aleo;
import one_program.aleo;
program two_program.aleo {
mapping counts: address => u64;
transition b() {
zero_program.aleo/c();
one_program.aleo/d();
return then finalize(self.signer);
}
finalize b(addr: address) {
let count: u64 = counts.get_or_use(addr, 0u64);
counts.set(addr, count + 1u64);
}
}
// --- Next Program --- //
import zero_program.aleo;
import one_program.aleo;
import two_program.aleo;
program three_program.aleo {
mapping counts: address => u64;
transition e() {
two_program.aleo/b();
one_program.aleo/d();
zero_program.aleo/c();
return then finalize(self.signer);
}
finalize e(addr: address) {
let count: u64 = counts.get_or_use(addr, 0u64);
counts.set(addr, count + 1u64);
}
}
// --- Next Program --- //
import two_program.aleo;
import three_program.aleo;
program four_program.aleo {
mapping counts: address => u64;
transition a() {
two_program.aleo/b();
three_program.aleo/e();
return then finalize(self.signer);
}
finalize a(addr: address) {
let count: u64 = counts.get_or_use(addr, 0u64);
counts.set(addr, count + 1u64);
}
}