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

Output bytecode for test cases. #28402

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
30 changes: 11 additions & 19 deletions Cargo.lock

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

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ features = [ "derive", "rc" ]
version = "1.0"
features = [ "preserve_order" ]

[workspace.dependencies.serde_yaml]
version = "0.9"

[workspace.dependencies.tracing]
version = "0.1"

Expand Down
2 changes: 1 addition & 1 deletion compiler/compiler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ workspace = true
workspace = true

[dev-dependencies.serde_yaml]
version = "0.8.25"
workspace = true

[dev-dependencies.tempfile]
version = "3.13"
Expand Down
3 changes: 1 addition & 2 deletions compiler/compiler/tests/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ use utilities::{
get_build_options,
get_cwd_option,
hash_asts,
hash_content,
hash_symbol_tables,
parse_program,
};
Expand Down Expand Up @@ -169,7 +168,7 @@ fn run_test(test: Test, handler: &Handler, buf: &BufferEmitter) -> Result<Value,
destructured_ast,
inlined_ast,
dce_ast,
bytecode: hash_content(&bytecode),
bytecode,
errors: buf.0.take().to_string(),
warnings: buf.1.take().to_string(),
};
Expand Down
8 changes: 4 additions & 4 deletions compiler/compiler/tests/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,17 +236,17 @@ fn run_test(test: Test, handler: &Handler, buf: &BufferEmitter) -> Result<Value,
// Run each test case for each function.
for case in all_cases {
let case = case.as_mapping().unwrap();
let program_name = case.get(&Value::from("program")).expect("expected program name").as_str().unwrap();
let function_name = case.get(&Value::from("function")).expect("expected function name").as_str().unwrap();
let program_name = case.get(Value::from("program")).expect("expected program name").as_str().unwrap();
let function_name = case.get(Value::from("function")).expect("expected function name").as_str().unwrap();
let inputs: Vec<_> = case
.get(&Value::from("input"))
.get(Value::from("input"))
.unwrap()
.as_sequence()
.unwrap()
.iter()
.map(|input| console::program::Value::<CurrentNetwork>::from_str(input.as_str().unwrap()).unwrap())
.collect();
let private_key = match case.get(&Value::from("private_key")) {
let private_key = match case.get(Value::from("private_key")) {
Some(private_key) => {
PrivateKey::from_str(private_key.as_str().expect("expected string for private key"))
.expect("unable to parse private key")
Expand Down
2 changes: 1 addition & 1 deletion compiler/compiler/tests/utilities/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ pub fn get_build_options(test_config: &TestConfig) -> Vec<BuildOptions> {
);
BuildOptions {
dce_enabled: config
.get(&serde_yaml::Value::String("dce_enabled".to_string()))
.get(serde_yaml::Value::String("dce_enabled".to_string()))
.expect("Expected key `dce_enabled`")
.as_bool()
.expect("Expected value to be a boolean."),
Expand Down
2 changes: 1 addition & 1 deletion compiler/parser/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ path = "../../tests/test-framework"
workspace = true

[dev-dependencies.serde_yaml]
version = "0.8"
workspace = true

[features]
default = [ ]
Expand Down
129 changes: 52 additions & 77 deletions compiler/passes/src/code_generation/visit_program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,18 @@ use leo_ast::{Composite, Function, Location, Mapping, Member, Mode, Program, Pro
use leo_span::{Symbol, sym};

use indexmap::IndexMap;
use itertools::Itertools;
use std::fmt::Write as _;

const EXPECT_STR: &str = "Failed to write code";

impl<'a> CodeGenerator<'a> {
pub(crate) fn visit_program(&mut self, input: &'a Program) -> String {
// Accumulate instructions into a program string.
let mut program_string = String::new();

// 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));
writeln!(program_string, "import {}.aleo;", program_name).expect(EXPECT_STR);
});

// Retrieve the program scope.
Expand All @@ -40,11 +41,7 @@ impl<'a> CodeGenerator<'a> {
self.program_id = Some(program_scope.program_id);

// Print the program id.
writeln!(program_string, "program {};", program_scope.program_id)
.expect("Failed to write program id to string.");

// Newline separator.
program_string.push('\n');
writeln!(program_string, "program {};", program_scope.program_id).expect(EXPECT_STR);

// Get the post-order ordering of the composite data types.
// Note that the unwrap is safe since type checking guarantees that the struct dependency graph is acyclic.
Expand All @@ -68,70 +65,50 @@ impl<'a> CodeGenerator<'a> {
.collect();

// Visit each `Struct` or `Record` in the post-ordering and produce an Aleo struct or record.
program_string.push_str(
&order
.into_iter()
.map(|name| {
match structs_map.get(&name) {
// If the struct is found, it is a struct or external record.
Some(struct_) => self.visit_struct_or_record(struct_),
// If the struct is not found, it is an imported record.
None => String::new(),
}
})
.join("\n"),
);

// Newline separator.
program_string.push('\n');
for name in order.into_iter() {
if let Some(struct_) = structs_map.get(&name) {
program_string.push_str(&self.visit_struct_or_record(struct_));
}
}

// Visit each mapping in the Leo AST and produce an Aleo mapping declaration.
program_string
.push_str(&program_scope.mappings.iter().map(|(_, mapping)| self.visit_mapping(mapping)).join("\n"));
for (_symbol, mapping) in program_scope.mappings.iter() {
program_string.push_str(&self.visit_mapping(mapping));
}

// Visit each function in the program scope and produce an Aleo function.
// Note that in the function inlining pass, we reorder the functions such that they are in post-order.
// In other words, a callee function precedes its caller function in the program scope.
program_string.push_str(
&program_scope
.functions
.iter()
.map(|(_, function)| {
if function.variant != Variant::AsyncFunction {
let mut function_string = self.visit_function(function);

// Attach the associated finalize to async transitions.
if function.variant == Variant::AsyncTransition {
// Set state variables.
self.finalize_caller = Some(function.identifier.name);
// Generate code for the associated finalize function.
let finalize = &self
.symbol_table
.lookup_fn_symbol(Location::new(
Some(self.program_id.unwrap().name.name),
function.identifier.name,
))
.unwrap()
.clone()
.finalize
.unwrap()
.name;
// Write the finalize string.
function_string.push_str(&format!(
"{}\n",
&self.visit_function(
&program_scope.functions.iter().find(|(name, _f)| name == finalize).unwrap().1
)
));
}

function_string
} else {
String::new()
}
})
.join("\n"),
);
for (_symbol, function) in program_scope.functions.iter() {
// program_string.push_str(&program_scope.functions.iter().map(|(_, function)| {
if function.variant != Variant::AsyncFunction {
let mut function_string = self.visit_function(function);

// Attach the associated finalize to async transitions.
if function.variant == Variant::AsyncTransition {
// Set state variables.
self.finalize_caller = Some(function.identifier.name);
// Generate code for the associated finalize function.
let finalize = &self
.symbol_table
.lookup_fn_symbol(Location::new(
Some(self.program_id.unwrap().name.name),
function.identifier.name,
))
.unwrap()
.clone()
.finalize
.unwrap()
.name;
// Write the finalize string.
function_string.push_str(&self.visit_function(
&program_scope.functions.iter().find(|(name, _f)| name == finalize).unwrap().1,
));
}

program_string.push_str(&function_string);
}
}

program_string
}
Expand All @@ -144,22 +121,21 @@ impl<'a> CodeGenerator<'a> {
// Add private symbol to composite types.
self.composite_mapping.insert(&struct_.identifier.name, (false, String::from("private"))); // todo: private by default here.

let mut output_string = format!("struct {}:\n", struct_.identifier); // todo: check if this is safe from name conflicts.
let mut output_string = format!("\nstruct {}:\n", struct_.identifier); // todo: check if this is safe from name conflicts.

// Construct and append the record variables.
for var in struct_.members.iter() {
writeln!(output_string, " {} as {};", var.identifier, Self::visit_type(&var.type_),)
.expect("failed to write to string");
writeln!(output_string, " {} as {};", var.identifier, Self::visit_type(&var.type_),).expect(EXPECT_STR);
}

output_string
}

fn visit_record(&mut self, record: &'a Composite) -> String {
// Add record symbol to composite types.
let mut output_string = String::from("record");
self.composite_mapping.insert(&record.identifier.name, (true, output_string.clone()));
writeln!(output_string, " {}:", record.identifier).expect("failed to write to string"); // todo: check if this is safe from name conflicts.
self.composite_mapping.insert(&record.identifier.name, (true, "record".into()));

let mut output_string = format!("\nrecord {}:\n", record.identifier); // todo: check if this is safe from name conflicts.

let mut members = Vec::with_capacity(record.members.len());
let mut member_map: IndexMap<Symbol, Member> =
Expand All @@ -185,7 +161,7 @@ impl<'a> CodeGenerator<'a> {
var.identifier,
Self::visit_type(&var.type_)
)
.expect("failed to write to string");
.expect(EXPECT_STR);
}

output_string
Expand All @@ -210,7 +186,7 @@ impl<'a> CodeGenerator<'a> {
Variant::Transition | Variant::AsyncTransition => format!("\nfunction {}:\n", function.identifier),
Variant::Function => format!("\nclosure {}:\n", function.identifier),
Variant::AsyncFunction => format!("\nfinalize {}:\n", self.finalize_caller.unwrap()),
Variant::Inline => return String::from("\n"),
Variant::Inline => return String::new(),
};

// Construct and append the input declarations of the function.
Expand Down Expand Up @@ -241,8 +217,7 @@ impl<'a> CodeGenerator<'a> {
}
};

writeln!(function_string, " input {register_string} as {type_string};",)
.expect("failed to write to string");
writeln!(function_string, " input {register_string} as {type_string};",).expect(EXPECT_STR);
}

// Construct and append the function body.
Expand Down Expand Up @@ -275,10 +250,10 @@ impl<'a> CodeGenerator<'a> {
};

// Create the key string, e.g. ` key as address.public`.
mapping_string.push_str(&format!("\tkey as {};\n", create_type(&mapping.key_type)));
writeln!(mapping_string, " key as {};", create_type(&mapping.key_type)).expect(EXPECT_STR);

// Create the value string, e.g. ` value as address.public`.
mapping_string.push_str(&format!("\tvalue as {};\n", create_type(&mapping.value_type)));
writeln!(mapping_string, " value as {};", create_type(&mapping.value_type)).expect(EXPECT_STR);

// Add the mapping to the variable mapping.
self.global_mapping.insert(&mapping.identifier.name, mapping.identifier.to_string());
Expand Down
35 changes: 20 additions & 15 deletions tests/expectations/compiler/address/binary.out
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
---
namespace: Compile
expectation: Pass
outputs:
- - compile:
- initial_symbol_table: 756e2b87734bb537caa46fae8a2b650aab26e96062df959e32e4828535c6affd
type_checked_symbol_table: d53bb8960397c6ee70314bcd5a30dbb59d655bda52b4937c16a94af0417fe793
unrolled_symbol_table: d53bb8960397c6ee70314bcd5a30dbb59d655bda52b4937c16a94af0417fe793
initial_ast: 3e0dce3c7ac38e237c811a557ddf5422d92024cd3a2f9a050f5089fb49e1c0d2
unrolled_ast: 3e0dce3c7ac38e237c811a557ddf5422d92024cd3a2f9a050f5089fb49e1c0d2
ssa_ast: e4e399f95f533afdcd018463d8a27bc573fcc02dfd11b0e32990e690b98584da
flattened_ast: 2b95ef75e175131a082bc796f2b57942c2fb395373c91ef5fbbf1ed70d80a2c3
destructured_ast: 6b932fa3264ea209145cb10679089bb14e6f5e667c8cff3b9adef16424e70646
inlined_ast: 6b932fa3264ea209145cb10679089bb14e6f5e667c8cff3b9adef16424e70646
dce_ast: 23001f440ab4c99e89ac05facdfe45b10206fcc86a80bb11f8108c9b3785151b
bytecode: e434c09cee27a5dfb5a4e9e9fd26aa2ba6e7f0653fad3a4f2a7d85983ba559c9
errors: ""
warnings: ""
- - compile:
- initial_symbol_table: 756e2b87734bb537caa46fae8a2b650aab26e96062df959e32e4828535c6affd
type_checked_symbol_table: d53bb8960397c6ee70314bcd5a30dbb59d655bda52b4937c16a94af0417fe793
unrolled_symbol_table: d53bb8960397c6ee70314bcd5a30dbb59d655bda52b4937c16a94af0417fe793
initial_ast: 3e0dce3c7ac38e237c811a557ddf5422d92024cd3a2f9a050f5089fb49e1c0d2
unrolled_ast: 3e0dce3c7ac38e237c811a557ddf5422d92024cd3a2f9a050f5089fb49e1c0d2
ssa_ast: e4e399f95f533afdcd018463d8a27bc573fcc02dfd11b0e32990e690b98584da
flattened_ast: 2b95ef75e175131a082bc796f2b57942c2fb395373c91ef5fbbf1ed70d80a2c3
destructured_ast: 6b932fa3264ea209145cb10679089bb14e6f5e667c8cff3b9adef16424e70646
inlined_ast: 6b932fa3264ea209145cb10679089bb14e6f5e667c8cff3b9adef16424e70646
dce_ast: 23001f440ab4c99e89ac05facdfe45b10206fcc86a80bb11f8108c9b3785151b
bytecode: |
program test.aleo;

function main:
input r0 as address.private;
is.neq r0 aleo1fj982yqchhy973kz7e9jk6er7t6qd6jm9anplnlprem507w6lv9spwvfxx into r1;
output r1 as boolean.private;
errors: ''
warnings: ''
Loading
Loading