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

Appending symbol table hashes to test expectations #2576

Merged
merged 8 commits into from
Sep 7, 2023
Merged
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
  •  
  •  
  •  
2 changes: 2 additions & 0 deletions Cargo.lock

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

4 changes: 2 additions & 2 deletions compiler/ast/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ impl AsRef<Program> for Ast {
}

/// Helper function to recursively filter keys from AST JSON
pub(crate) fn remove_key_from_json(value: serde_json::Value, key: &str) -> serde_json::Value {
pub fn remove_key_from_json(value: serde_json::Value, key: &str) -> serde_json::Value {
match value {
serde_json::Value::Object(map) => serde_json::Value::Object(
map.into_iter().filter(|(k, _)| k != key).map(|(k, v)| (k, remove_key_from_json(v, key))).collect(),
Expand All @@ -170,7 +170,7 @@ pub(crate) fn remove_key_from_json(value: serde_json::Value, key: &str) -> serde
/// 1. Remove empty object mappings from JSON arrays
/// 2. If there are two elements in a JSON array and one is an empty object
/// mapping and the other is not, then lift up the one that isn't
pub(crate) fn normalize_json_value(value: serde_json::Value) -> serde_json::Value {
pub fn normalize_json_value(value: serde_json::Value) -> serde_json::Value {
match value {
serde_json::Value::Array(vec) => {
let orig_length = vec.len();
Expand Down
38 changes: 33 additions & 5 deletions compiler/compiler/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ impl<'a> Compiler<'a> {
leo_parser::parse_input(self.handler, &self.node_builder, &input_sf.src, input_sf.start_pos)?;
if self.compiler_options.output.initial_ast {
// Write the input AST snapshot post parsing.
if self.compiler_options.output.spans_enabled {
if self.compiler_options.output.ast_spans_enabled {
input_ast.to_json_file(
self.output_directory.clone(),
&format!("{}.initial_input_ast.json", self.program_name),
Expand All @@ -165,12 +165,20 @@ impl<'a> Compiler<'a> {

/// Runs the symbol table pass.
pub fn symbol_table_pass(&self) -> Result<SymbolTable> {
SymbolTableCreator::do_pass((&self.ast, self.handler))
let symbol_table = SymbolTableCreator::do_pass((&self.ast, self.handler))?;
if self.compiler_options.output.initial_symbol_table {
self.write_symbol_table_to_json("initial_symbol_table.json", &symbol_table)?;
}
Ok(symbol_table)
}

/// Runs the type checker pass.
pub fn type_checker_pass(&'a self, symbol_table: SymbolTable) -> Result<(SymbolTable, StructGraph, CallGraph)> {
TypeChecker::do_pass((&self.ast, self.handler, symbol_table))
let (symbol_table, struct_graph, call_graph) = TypeChecker::do_pass((&self.ast, self.handler, symbol_table))?;
if self.compiler_options.output.type_checked_symbol_table {
self.write_symbol_table_to_json("type_checked_symbol_table.json", &symbol_table)?;
}
Ok((symbol_table, struct_graph, call_graph))
}

/// Runs the loop unrolling pass.
Expand All @@ -183,6 +191,10 @@ impl<'a> Compiler<'a> {
self.write_ast_to_json("unrolled_ast.json")?;
}

if self.compiler_options.output.unrolled_symbol_table {
self.write_symbol_table_to_json("unrolled_symbol_table.json", &symbol_table)?;
}

Ok(symbol_table)
}

Expand Down Expand Up @@ -283,13 +295,29 @@ impl<'a> Compiler<'a> {
/// Writes the AST to a JSON file.
fn write_ast_to_json(&self, file_suffix: &str) -> Result<()> {
// Remove `Span`s if they are not enabled.
if self.compiler_options.output.spans_enabled {
if self.compiler_options.output.ast_spans_enabled {
self.ast.to_json_file(self.output_directory.clone(), &format!("{}.{file_suffix}", self.program_name))?;
} else {
self.ast.to_json_file_without_keys(
self.output_directory.clone(),
&format!("{}.{file_suffix}", self.program_name),
&["span"],
&["_span", "span"],
)?;
}
Ok(())
}

/// Writes the Symbol Table to a JSON file.
fn write_symbol_table_to_json(&self, file_suffix: &str, symbol_table: &SymbolTable) -> Result<()> {
// Remove `Span`s if they are not enabled.
if self.compiler_options.output.symbol_table_spans_enabled {
symbol_table
.to_json_file(self.output_directory.clone(), &format!("{}.{file_suffix}", self.program_name))?;
} else {
symbol_table.to_json_file_without_keys(
self.output_directory.clone(),
&format!("{}.{file_suffix}", self.program_name),
&["_span", "span"],
)?;
}
Ok(())
Expand Down
10 changes: 9 additions & 1 deletion compiler/compiler/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,16 @@ pub struct BuildOptions {

#[derive(Clone, Default)]
pub struct OutputOptions {
//// Whether spans are enabled in the output symbol tables.
pub symbol_table_spans_enabled: bool,
// If enabled writes the symbol table after symbol table pass
pub initial_symbol_table: bool,
/// If enabled writes the symbol table after type checking.
pub type_checked_symbol_table: bool,
/// If enabled writes the symbol table after loop unrolling.
pub unrolled_symbol_table: bool,
/// Whether spans are enabled in the output ASTs.
pub spans_enabled: bool,
pub ast_spans_enabled: bool,
/// If enabled writes the AST after parsing.
pub initial_ast: bool,
/// If enabled writes the input AST after parsing.
Expand Down
16 changes: 15 additions & 1 deletion compiler/compiler/tests/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use utilities::{
get_cwd_option,
hash_asts,
hash_content,
hash_symbol_tables,
parse_program,
setup_build_directory,
BufferEmitter,
Expand Down Expand Up @@ -58,6 +59,9 @@ impl Namespace for CompileNamespace {

#[derive(Deserialize, PartialEq, Eq, Serialize)]
struct CompileOutput {
pub initial_symbol_table: String,
pub type_checked_symbol_table: String,
pub unrolled_symbol_table: String,
pub initial_ast: String,
pub unrolled_ast: String,
pub ssa_ast: String,
Expand All @@ -81,7 +85,11 @@ fn run_test(test: Test, handler: &Handler, buf: &BufferEmitter) -> Result<Value,
let compiler_options = CompilerOptions {
build,
output: OutputOptions {
spans_enabled: false,
symbol_table_spans_enabled: false,
initial_symbol_table: true,
type_checked_symbol_table: true,
unrolled_symbol_table: true,
ast_spans_enabled: false,
initial_input_ast: true,
initial_ast: true,
unrolled_ast: true,
Expand Down Expand Up @@ -110,12 +118,18 @@ fn run_test(test: Test, handler: &Handler, buf: &BufferEmitter) -> Result<Value,
// Hash the ast files.
let (initial_ast, unrolled_ast, ssa_ast, flattened_ast, inlined_ast, dce_ast) = hash_asts();

// Hash the symbol tables.
let (initial_symbol_table, type_checked_symbol_table, unrolled_symbol_table) = hash_symbol_tables();

// Clean up the output directory.
if fs::read_dir("/tmp/output").is_ok() {
fs::remove_dir_all(Path::new("/tmp/output")).expect("Error failed to clean up output dir.");
}

let final_output = CompileOutput {
initial_symbol_table,
type_checked_symbol_table,
unrolled_symbol_table,
initial_ast,
unrolled_ast,
ssa_ast,
Expand Down
16 changes: 15 additions & 1 deletion compiler/compiler/tests/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use utilities::{
get_cwd_option,
hash_asts,
hash_content,
hash_symbol_tables,
parse_program,
setup_build_directory,
Aleo,
Expand Down Expand Up @@ -66,6 +67,9 @@ impl Namespace for ExecuteNamespace {
// TODO: Format this better.
#[derive(Deserialize, PartialEq, Eq, Serialize)]
struct ExecuteOutput {
pub initial_symbol_table: String,
pub type_checked_symbol_table: String,
pub unrolled_symbol_table: String,
pub initial_ast: String,
pub unrolled_ast: String,
pub ssa_ast: String,
Expand Down Expand Up @@ -95,7 +99,11 @@ fn run_test(test: Test, handler: &Handler, err_buf: &BufferEmitter) -> Result<Va
let compiler_options = CompilerOptions {
build,
output: OutputOptions {
spans_enabled: false,
symbol_table_spans_enabled: false,
initial_symbol_table: true,
type_checked_symbol_table: true,
unrolled_symbol_table: true,
ast_spans_enabled: false,
initial_input_ast: true,
initial_ast: true,
unrolled_ast: true,
Expand Down Expand Up @@ -192,12 +200,18 @@ fn run_test(test: Test, handler: &Handler, err_buf: &BufferEmitter) -> Result<Va
// Hash the ast files.
let (initial_ast, unrolled_ast, ssa_ast, flattened_ast, inlined_ast, dce_ast) = hash_asts();

// Hash the symbol tables.
let (initial_symbol_table, type_checked_symbol_table, unrolled_symbol_table) = hash_symbol_tables();

// Clean up the output directory.
if fs::read_dir("/tmp/output").is_ok() {
fs::remove_dir_all(Path::new("/tmp/output")).expect("Error failed to clean up output dir.");
}

let final_output = ExecuteOutput {
initial_symbol_table,
type_checked_symbol_table,
unrolled_symbol_table,
initial_ast,
unrolled_ast,
ssa_ast,
Expand Down
7 changes: 7 additions & 0 deletions compiler/compiler/tests/utilities/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,13 @@ pub fn hash_asts() -> (String, String, String, String, String, String) {
(initial_ast, unrolled_ast, ssa_ast, flattened_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");
(initial_symbol_table, type_checked_symbol_table, unrolled_symbol_table)
}

pub fn get_cwd_option(test: &Test) -> Option<PathBuf> {
// Check for CWD option:
// ``` cwd: import ```
Expand Down
8 changes: 8 additions & 0 deletions compiler/passes/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,11 @@ version = "0.11.0"

[dependencies.num-traits]
version = "0.2.16"

[dependencies.serde]
version = "1.0"
features = [ "derive", "rc" ]

[dependencies.serde_json]
version = "1.0"
features = [ "preserve_order" ]
6 changes: 4 additions & 2 deletions compiler/passes/src/common/symbol_table/function_symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@
use leo_ast::{Function, Input, Type, Variant};
use leo_span::Span;

use serde::{Deserialize, Serialize};

use crate::SymbolTable;

/// Metadata associated with the finalize block.
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FinalizeData {
/// The inputs to the finalize block.
pub(crate) input: Vec<Input>,
Expand All @@ -29,7 +31,7 @@ pub struct FinalizeData {
}

/// An entry for a function in the symbol table.
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct FunctionSymbol {
/// The index associated with the scope in the parent symbol table.
pub(crate) id: usize,
Expand Down
62 changes: 60 additions & 2 deletions compiler/passes/src/common/symbol_table/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@ pub use variable_symbol::*;

use std::cell::RefCell;

use leo_ast::{Function, Struct};
use leo_ast::{normalize_json_value, remove_key_from_json, Function, Struct};
use leo_errors::{AstError, Result};
use leo_span::{Span, Symbol};

use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
use serde_json;

#[derive(Clone, Debug, Default)]
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct SymbolTable {
/// The parent scope if it exists.
/// For example, the parent scope of a then-block is the scope containing the associated ConditionalStatement.
Expand Down Expand Up @@ -172,4 +174,60 @@ impl SymbolTable {
pub fn lookup_scope_by_index(&self, index: usize) -> Option<&RefCell<Self>> {
self.scopes.get(index)
}

/// Serializes the symbol table into a JSON string.
pub fn to_json_string(&self) -> Result<String> {
Ok(serde_json::to_string_pretty(&self)
.map_err(|e| AstError::failed_to_convert_symbol_table_to_json_string(&e))?)
}

/// Converts the symbol table into a JSON value
pub fn to_json_value(&self) -> Result<serde_json::Value> {
Ok(serde_json::to_value(self).map_err(|e| AstError::failed_to_convert_symbol_table_to_json_value(&e))?)
}

// Serializes the symbol table into a JSON file.
pub fn to_json_file(&self, mut path: std::path::PathBuf, file_name: &str) -> Result<()> {
path.push(file_name);
let file =
std::fs::File::create(&path).map_err(|e| AstError::failed_to_create_symbol_table_json_file(&path, &e))?;
let writer = std::io::BufWriter::new(file);
Ok(serde_json::to_writer_pretty(writer, &self)
.map_err(|e| AstError::failed_to_write_symbol_table_to_json_file(&path, &e))?)
}

/// Serializes the symbol table into a JSON value and removes keys from object mappings before writing to a file.
pub fn to_json_file_without_keys(
&self,
mut path: std::path::PathBuf,
file_name: &str,
excluded_keys: &[&str],
) -> Result<()> {
path.push(file_name);
let file =
std::fs::File::create(&path).map_err(|e| AstError::failed_to_create_symbol_table_json_file(&path, &e))?;
let writer = std::io::BufWriter::new(file);

let mut value = self.to_json_value().unwrap();
for key in excluded_keys {
value = remove_key_from_json(value, key);
}
value = normalize_json_value(value);

Ok(serde_json::to_writer_pretty(writer, &value)
.map_err(|e| AstError::failed_to_write_symbol_table_to_json_file(&path, &e))?)
}

/// Deserializes the JSON string into a symbol table.
pub fn from_json_string(json: &str) -> Result<Self> {
let symbol_table: SymbolTable =
serde_json::from_str(json).map_err(|e| AstError::failed_to_read_json_string_to_symbol_table(&e))?;
Ok(symbol_table)
}

/// Deserializes the JSON string into a symbol table from a file.
pub fn from_json_file(path: std::path::PathBuf) -> Result<Self> {
let data = std::fs::read_to_string(&path).map_err(|e| AstError::failed_to_read_json_file(&path, &e))?;
Self::from_json_string(&data)
}
}
6 changes: 4 additions & 2 deletions compiler/passes/src/common/symbol_table/variable_symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@

use std::fmt::Display;

use serde::{Deserialize, Serialize};

use leo_ast::{Mode, Type};
use leo_span::Span;

/// An enumeration of the different types of variable type.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum VariableType {
Const,
Input(Mode),
Expand All @@ -40,7 +42,7 @@ impl Display for VariableType {
}

/// An entry for a variable in the symbol table.
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct VariableSymbol {
/// The `Type` of the variable.
pub type_: Type,
Expand Down
Loading
Loading