This commit is contained in:
Pranav Gaddamadugu 2023-10-10 20:25:06 -04:00
parent b8a41e483d
commit 4778fe6405
7 changed files with 44 additions and 37 deletions

View File

@ -142,18 +142,18 @@ impl StatementReconstructor for Flattener<'_> {
} }
} }
/// Flattens an assign statement, if necessary. /// Flattens a definition statement, if necessary.
/// Marks variables as structs as necessary. /// Marks variables as structs as necessary.
/// Note that new statements are only produced if the right hand side is a ternary expression over structs. /// Note that new statements are only produced if the right hand side is a ternary expression over structs.
/// Otherwise, the statement is returned as is. /// Otherwise, the statement is returned as is.
fn reconstruct_assign(&mut self, assign: AssignStatement) -> (Statement, Self::AdditionalOutput) { fn reconstruct_definition(&mut self, definition: DefinitionStatement) -> (Statement, Self::AdditionalOutput) {
// Flatten the rhs of the assignment. // Flatten the rhs of the definition.
let (value, mut statements) = self.reconstruct_expression(assign.value); let (value, mut statements) = self.reconstruct_expression(definition.value);
match (assign.place, value.clone()) { match (definition.place, value.clone()) {
// If the lhs is an identifier and the rhs is a tuple, then add the tuple to `self.tuples`. // If the lhs is an identifier and the rhs is a tuple, then add the tuple to `self.tuples`.
(Expression::Identifier(identifier), Expression::Tuple(tuple)) => { (Expression::Identifier(identifier), Expression::Tuple(tuple)) => {
self.tuples.insert(identifier.name, tuple); self.tuples.insert(identifier.name, tuple);
// Note that tuple assignments are removed from the AST. // Note that tuple definitions are removed from the AST.
(Statement::dummy(Default::default(), self.node_builder.next_id()), statements) (Statement::dummy(Default::default(), self.node_builder.next_id()), statements)
} }
// If the lhs is an identifier and the rhs is an identifier that is a tuple, then add it to `self.tuples`. // If the lhs is an identifier and the rhs is an identifier that is a tuple, then add it to `self.tuples`.
@ -163,7 +163,7 @@ impl StatementReconstructor for Flattener<'_> {
// Lookup the entry in `self.tuples` and add it for the lhs of the assignment. // Lookup the entry in `self.tuples` and add it for the lhs of the assignment.
// Note that the `unwrap` is safe since the match arm checks that the entry exists. // Note that the `unwrap` is safe since the match arm checks that the entry exists.
self.tuples.insert(lhs_identifier.name, self.tuples.get(&rhs_identifier.name).unwrap().clone()); self.tuples.insert(lhs_identifier.name, self.tuples.get(&rhs_identifier.name).unwrap().clone());
// Note that tuple assignments are removed from the AST. // Note that tuple definitions are removed from the AST.
(Statement::dummy(Default::default(), self.node_builder.next_id()), statements) (Statement::dummy(Default::default(), self.node_builder.next_id()), statements)
} }
// If the lhs is an identifier and the rhs is a function call that produces a tuple, then add it to `self.tuples`. // If the lhs is an identifier and the rhs is a function call that produces a tuple, then add it to `self.tuples`.
@ -185,7 +185,7 @@ impl StatementReconstructor for Flattener<'_> {
.zip_eq(tuple.0.iter()) .zip_eq(tuple.0.iter())
.map(|(i, type_)| { .map(|(i, type_)| {
let identifier = Identifier::new( let identifier = Identifier::new(
self.assigner.unique_symbol(lhs_identifier.name, format!("$index${i}$")), self.definer.unique_symbol(lhs_identifier.name, format!("$index${i}$")),
self.node_builder.next_id(), self.node_builder.next_id(),
); );
@ -281,7 +281,10 @@ impl StatementReconstructor for Flattener<'_> {
} }
(Expression::Identifier(identifier), expression) => { (Expression::Identifier(identifier), expression) => {
self.update_structs(&identifier, &expression); self.update_structs(&identifier, &expression);
(self.assigner.simple_assign_statement(identifier, expression, self.node_builder.next_id()), statements) (
self.definer.simple_definition_statement(identifier, expression, self.node_builder.next_id()),
statements,
)
} }
// If the lhs is a tuple and the rhs is a function call, then return the reconstructed statement. // If the lhs is a tuple and the rhs is a function call, then return the reconstructed statement.
(Expression::Tuple(tuple), Expression::Call(call)) => { (Expression::Tuple(tuple), Expression::Call(call)) => {
@ -429,9 +432,9 @@ impl StatementReconstructor for Flattener<'_> {
unreachable!("`ConsoleStatement`s should not be in the AST at this phase of compilation.") unreachable!("`ConsoleStatement`s should not be in the AST at this phase of compilation.")
} }
/// Static single assignment converts definition statements into assignment statements. /// Static single assignment converts assignment statements into definition statements.
fn reconstruct_definition(&mut self, _definition: DefinitionStatement) -> (Statement, Self::AdditionalOutput) { fn reconstruct_assign(&mut self, _: AssignStatement) -> (Statement, Self::AdditionalOutput) {
unreachable!("`DefinitionStatement`s should not exist in the AST at this phase of compilation.") unreachable!("`AssignStatement`s should not exist in the AST at this phase of compilation.")
} }
// TODO: Error message requesting the user to enable loop-unrolling. // TODO: Error message requesting the user to enable loop-unrolling.

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // 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/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{Assigner, SymbolTable}; use crate::{Definer, SymbolTable};
use leo_ast::{ use leo_ast::{
AccessExpression, AccessExpression,
@ -41,8 +41,8 @@ pub struct Flattener<'a> {
pub(crate) symbol_table: &'a SymbolTable, pub(crate) symbol_table: &'a SymbolTable,
/// A counter used to generate unique node IDs. /// A counter used to generate unique node IDs.
pub(crate) node_builder: &'a NodeBuilder, pub(crate) node_builder: &'a NodeBuilder,
/// A struct used to construct (unique) assignment statements. /// A struct used to construct (unique) definition statements.
pub(crate) assigner: &'a Assigner, pub(crate) definer: &'a Definer,
/// The set of variables that are structs. /// The set of variables that are structs.
pub(crate) structs: IndexMap<Symbol, Symbol>, pub(crate) structs: IndexMap<Symbol, Symbol>,
/// A stack of condition `Expression`s visited up to the current point in the AST. /// A stack of condition `Expression`s visited up to the current point in the AST.
@ -57,11 +57,11 @@ pub struct Flattener<'a> {
} }
impl<'a> Flattener<'a> { impl<'a> Flattener<'a> {
pub(crate) fn new(symbol_table: &'a SymbolTable, node_builder: &'a NodeBuilder, assigner: &'a Assigner) -> Self { pub(crate) fn new(symbol_table: &'a SymbolTable, node_builder: &'a NodeBuilder, assigner: &'a Definer) -> Self {
Self { Self {
symbol_table, symbol_table,
node_builder, node_builder,
assigner, definer: assigner,
structs: IndexMap::new(), structs: IndexMap::new(),
condition_stack: Vec::new(), condition_stack: Vec::new(),
returns: Vec::new(), returns: Vec::new(),
@ -115,7 +115,7 @@ impl<'a> Flattener<'a> {
let mut construct_ternary_assignment = let mut construct_ternary_assignment =
|guard: Expression, if_true: Expression, if_false: Expression| { |guard: Expression, if_true: Expression, if_false: Expression| {
let place = Identifier { let place = Identifier {
name: self.assigner.unique_symbol(prefix, "$"), name: self.definer.unique_symbol(prefix, "$"),
span: Default::default(), span: Default::default(),
id: self.node_builder.next_id(), id: self.node_builder.next_id(),
}; };
@ -190,11 +190,11 @@ impl<'a> Flattener<'a> {
/// A wrapper around `assigner.unique_simple_assign_statement` that updates `self.structs`. /// A wrapper around `assigner.unique_simple_assign_statement` that updates `self.structs`.
pub(crate) fn unique_simple_assign_statement(&mut self, expr: Expression) -> (Identifier, Statement) { pub(crate) fn unique_simple_assign_statement(&mut self, expr: Expression) -> (Identifier, Statement) {
// Create a new variable for the expression. // Create a new variable for the expression.
let name = self.assigner.unique_symbol("$var", "$"); let name = self.definer.unique_symbol("$var", "$");
// Construct the lhs of the assignment. // Construct the lhs of the assignment.
let place = Identifier { name, span: Default::default(), id: self.node_builder.next_id() }; let place = Identifier { name, span: Default::default(), id: self.node_builder.next_id() };
// Construct the assignment statement. // Construct the assignment statement.
let statement = self.assigner.simple_assign_statement(place, expr, self.node_builder.next_id()); let statement = self.definer.simple_definition_statement(place, expr, self.node_builder.next_id());
match &statement { match &statement {
Statement::Assign(assign) => { Statement::Assign(assign) => {
@ -208,7 +208,7 @@ impl<'a> Flattener<'a> {
/// A wrapper around `assigner.simple_assign_statement` that updates `self.structs`. /// A wrapper around `assigner.simple_assign_statement` that updates `self.structs`.
pub(crate) fn simple_assign_statement(&mut self, lhs: Identifier, rhs: Expression) -> Statement { pub(crate) fn simple_assign_statement(&mut self, lhs: Identifier, rhs: Expression) -> Statement {
self.update_structs(&lhs, &rhs); self.update_structs(&lhs, &rhs);
self.assigner.simple_assign_statement(lhs, rhs, self.node_builder.next_id()) self.definer.simple_definition_statement(lhs, rhs, self.node_builder.next_id())
} }
/// Folds a list of return statements into a single return statement and adds the produced statements to the block. /// Folds a list of return statements into a single return statement and adds the produced statements to the block.

View File

@ -59,13 +59,13 @@ mod flatten_statement;
pub mod flattener; pub mod flattener;
pub use flattener::*; pub use flattener::*;
use crate::{Assigner, Pass, SymbolTable}; use crate::{Definer, Pass, SymbolTable};
use leo_ast::{Ast, NodeBuilder, ProgramReconstructor}; use leo_ast::{Ast, NodeBuilder, ProgramReconstructor};
use leo_errors::Result; use leo_errors::Result;
impl<'a> Pass for Flattener<'a> { impl<'a> Pass for Flattener<'a> {
type Input = (Ast, &'a SymbolTable, &'a NodeBuilder, &'a Assigner); type Input = (Ast, &'a SymbolTable, &'a NodeBuilder, &'a Definer);
type Output = Result<Ast>; type Output = Result<Ast>;
fn do_pass((ast, st, node_builder, assigner): Self::Input) -> Self::Output { fn do_pass((ast, st, node_builder, assigner): Self::Input) -> Self::Output {

View File

@ -59,13 +59,13 @@ mod rename_statement;
pub mod static_single_assigner; pub mod static_single_assigner;
pub use static_single_assigner::*; pub use static_single_assigner::*;
use crate::{Assigner, Pass, SymbolTable}; use crate::{Definer, Pass, SymbolTable};
use leo_ast::{Ast, NodeBuilder, ProgramConsumer}; use leo_ast::{Ast, NodeBuilder, ProgramConsumer};
use leo_errors::Result; use leo_errors::Result;
impl<'a> Pass for StaticSingleAssigner<'a> { impl<'a> Pass for StaticSingleAssigner<'a> {
type Input = (Ast, &'a NodeBuilder, &'a Assigner, &'a SymbolTable); type Input = (Ast, &'a NodeBuilder, &'a Definer, &'a SymbolTable);
type Output = Result<Ast>; type Output = Result<Ast>;
fn do_pass((ast, node_builder, assigner, symbol_table): Self::Input) -> Self::Output { fn do_pass((ast, node_builder, assigner, symbol_table): Self::Input) -> Self::Output {

View File

@ -255,7 +255,7 @@ impl ExpressionConsumer for StaticSingleAssigner<'_> {
let name = match self.is_lhs { let name = match self.is_lhs {
// If consuming the left-hand side of a definition or assignment, a new unique name is introduced. // If consuming the left-hand side of a definition or assignment, a new unique name is introduced.
true => { true => {
let new_name = self.assigner.unique_symbol(identifier.name, "$"); let new_name = self.definer.unique_symbol(identifier.name, "$");
self.rename_table.update(identifier.name, new_name); self.rename_table.update(identifier.name, new_name);
new_name new_name
} }

View File

@ -95,7 +95,7 @@ impl StatementConsumer for StaticSingleAssigner<'_> {
}; };
self.is_lhs = false; self.is_lhs = false;
statements.push(self.assigner.simple_assign_statement(place, value, self.node_builder.next_id())); statements.push(self.definer.simple_definition_statement(place, value, self.node_builder.next_id()));
statements statements
} }
@ -180,7 +180,7 @@ impl StatementConsumer for StaticSingleAssigner<'_> {
}; };
// Create a new name for the variable written to in the `ConditionalStatement`. // Create a new name for the variable written to in the `ConditionalStatement`.
let new_name = self.assigner.unique_symbol(symbol, "$"); let new_name = self.definer.unique_symbol(symbol, "$");
let (value, stmts) = self.consume_ternary(TernaryExpression { let (value, stmts) = self.consume_ternary(TernaryExpression {
condition: Box::new(condition.clone()), condition: Box::new(condition.clone()),
@ -193,7 +193,7 @@ impl StatementConsumer for StaticSingleAssigner<'_> {
statements.extend(stmts); statements.extend(stmts);
// Create a new `AssignStatement` for the phi function. // Create a new `AssignStatement` for the phi function.
let assignment = self.assigner.simple_assign_statement( let assignment = self.definer.simple_definition_statement(
Identifier { name: new_name, span: Default::default(), id: self.node_builder.next_id() }, Identifier { name: new_name, span: Default::default(), id: self.node_builder.next_id() },
value, value,
self.node_builder.next_id(), self.node_builder.next_id(),
@ -233,7 +233,11 @@ impl StatementConsumer for StaticSingleAssigner<'_> {
Expression::Identifier(identifier) => identifier, Expression::Identifier(identifier) => identifier,
_ => unreachable!("`self.consume_identifier` will always return an `Identifier`."), _ => unreachable!("`self.consume_identifier` will always return an `Identifier`."),
}; };
statements.push(self.assigner.simple_assign_statement(identifier, value, self.node_builder.next_id())); statements.push(self.definer.simple_definition_statement(
identifier,
value,
self.node_builder.next_id(),
));
} }
Expression::Tuple(tuple) => { Expression::Tuple(tuple) => {
let elements = tuple.elements.into_iter().map(|element| { let elements = tuple.elements.into_iter().map(|element| {

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // 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/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{Assigner, RenameTable, SymbolTable}; use crate::{Definer, RenameTable, SymbolTable};
use leo_ast::{Expression, Identifier, NodeBuilder, Statement}; use leo_ast::{Expression, Identifier, NodeBuilder, Statement};
@ -27,14 +27,14 @@ pub struct StaticSingleAssigner<'a> {
pub(crate) rename_table: RenameTable, pub(crate) rename_table: RenameTable,
/// A flag to determine whether or not the traversal is on the left-hand side of a definition or an assignment. /// A flag to determine whether or not the traversal is on the left-hand side of a definition or an assignment.
pub(crate) is_lhs: bool, pub(crate) is_lhs: bool,
/// A struct used to construct (unique) assignment statements. /// A struct used to construct (unique) definition statements.
pub(crate) assigner: &'a Assigner, pub(crate) definer: &'a Definer,
} }
impl<'a> StaticSingleAssigner<'a> { impl<'a> StaticSingleAssigner<'a> {
/// Initializes a new `StaticSingleAssigner` with an empty `RenameTable`. /// Initializes a new `StaticSingleAssigner` with an empty `RenameTable`.
pub(crate) fn new(node_builder: &'a NodeBuilder, symbol_table: &'a SymbolTable, assigner: &'a Assigner) -> Self { pub(crate) fn new(node_builder: &'a NodeBuilder, symbol_table: &'a SymbolTable, definer: &'a Definer) -> Self {
Self { node_builder, symbol_table, rename_table: RenameTable::new(None), is_lhs: false, assigner } Self { node_builder, symbol_table, rename_table: RenameTable::new(None), is_lhs: false, definer }
} }
/// Pushes a new scope, setting the current scope as the new scope's parent. /// Pushes a new scope, setting the current scope as the new scope's parent.
@ -54,13 +54,13 @@ impl<'a> StaticSingleAssigner<'a> {
/// The lhs is guaranteed to be unique with respect to the `Assigner`. /// The lhs is guaranteed to be unique with respect to the `Assigner`.
pub(crate) fn unique_simple_assign_statement(&mut self, expr: Expression) -> (Identifier, Statement) { pub(crate) fn unique_simple_assign_statement(&mut self, expr: Expression) -> (Identifier, Statement) {
// Create a new variable for the expression. // Create a new variable for the expression.
let name = self.assigner.unique_symbol("$var", "$"); let name = self.definer.unique_symbol("$var", "$");
// Create a new identifier for the variable. // Create a new identifier for the variable.
let place = Identifier { name, span: Default::default(), id: self.node_builder.next_id() }; let place = Identifier { name, span: Default::default(), id: self.node_builder.next_id() };
// Construct the statement. // Construct the statement.
let statement = self.assigner.simple_assign_statement(place, expr, self.node_builder.next_id()); let statement = self.definer.simple_definition_statement(place, expr, self.node_builder.next_id());
// Construct the identifier to be returned. Note that it must have a unique node ID. // Construct the identifier to be returned. Note that it must have a unique node ID.
let identifier = Identifier { name, span: Default::default(), id: self.node_builder.next_id() }; let identifier = Identifier { name, span: Default::default(), id: self.node_builder.next_id() };