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.
/// 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.
fn reconstruct_assign(&mut self, assign: AssignStatement) -> (Statement, Self::AdditionalOutput) {
// Flatten the rhs of the assignment.
let (value, mut statements) = self.reconstruct_expression(assign.value);
match (assign.place, value.clone()) {
fn reconstruct_definition(&mut self, definition: DefinitionStatement) -> (Statement, Self::AdditionalOutput) {
// Flatten the rhs of the definition.
let (value, mut statements) = self.reconstruct_expression(definition.value);
match (definition.place, value.clone()) {
// 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)) => {
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)
}
// 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.
// 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());
// 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)
}
// 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())
.map(|(i, type_)| {
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(),
);
@ -281,7 +281,10 @@ impl StatementReconstructor for Flattener<'_> {
}
(Expression::Identifier(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.
(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.")
}
/// Static single assignment converts definition statements into assignment statements.
fn reconstruct_definition(&mut self, _definition: DefinitionStatement) -> (Statement, Self::AdditionalOutput) {
unreachable!("`DefinitionStatement`s should not exist in the AST at this phase of compilation.")
/// Static single assignment converts assignment statements into definition statements.
fn reconstruct_assign(&mut self, _: AssignStatement) -> (Statement, Self::AdditionalOutput) {
unreachable!("`AssignStatement`s should not exist in the AST at this phase of compilation.")
}
// 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
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{Assigner, SymbolTable};
use crate::{Definer, SymbolTable};
use leo_ast::{
AccessExpression,
@ -41,8 +41,8 @@ pub struct Flattener<'a> {
pub(crate) symbol_table: &'a SymbolTable,
/// A counter used to generate unique node IDs.
pub(crate) node_builder: &'a NodeBuilder,
/// A struct used to construct (unique) assignment statements.
pub(crate) assigner: &'a Assigner,
/// A struct used to construct (unique) definition statements.
pub(crate) definer: &'a Definer,
/// The set of variables that are structs.
pub(crate) structs: IndexMap<Symbol, Symbol>,
/// 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> {
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 {
symbol_table,
node_builder,
assigner,
definer: assigner,
structs: IndexMap::new(),
condition_stack: Vec::new(),
returns: Vec::new(),
@ -115,7 +115,7 @@ impl<'a> Flattener<'a> {
let mut construct_ternary_assignment =
|guard: Expression, if_true: Expression, if_false: Expression| {
let place = Identifier {
name: self.assigner.unique_symbol(prefix, "$"),
name: self.definer.unique_symbol(prefix, "$"),
span: Default::default(),
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`.
pub(crate) fn unique_simple_assign_statement(&mut self, expr: Expression) -> (Identifier, Statement) {
// 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.
let place = Identifier { name, span: Default::default(), id: self.node_builder.next_id() };
// 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 {
Statement::Assign(assign) => {
@ -208,7 +208,7 @@ impl<'a> Flattener<'a> {
/// A wrapper around `assigner.simple_assign_statement` that updates `self.structs`.
pub(crate) fn simple_assign_statement(&mut self, lhs: Identifier, rhs: Expression) -> Statement {
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.

View File

@ -59,13 +59,13 @@ mod flatten_statement;
pub mod flattener;
pub use flattener::*;
use crate::{Assigner, Pass, SymbolTable};
use crate::{Definer, Pass, SymbolTable};
use leo_ast::{Ast, NodeBuilder, ProgramReconstructor};
use leo_errors::Result;
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>;
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 use static_single_assigner::*;
use crate::{Assigner, Pass, SymbolTable};
use crate::{Definer, Pass, SymbolTable};
use leo_ast::{Ast, NodeBuilder, ProgramConsumer};
use leo_errors::Result;
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>;
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 {
// If consuming the left-hand side of a definition or assignment, a new unique name is introduced.
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);
new_name
}

View File

@ -95,7 +95,7 @@ impl StatementConsumer for StaticSingleAssigner<'_> {
};
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
}
@ -180,7 +180,7 @@ impl StatementConsumer for StaticSingleAssigner<'_> {
};
// 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 {
condition: Box::new(condition.clone()),
@ -193,7 +193,7 @@ impl StatementConsumer for StaticSingleAssigner<'_> {
statements.extend(stmts);
// 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() },
value,
self.node_builder.next_id(),
@ -233,7 +233,11 @@ impl StatementConsumer for StaticSingleAssigner<'_> {
Expression::Identifier(identifier) => 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) => {
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
// 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};
@ -27,14 +27,14 @@ pub struct StaticSingleAssigner<'a> {
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.
pub(crate) is_lhs: bool,
/// A struct used to construct (unique) assignment statements.
pub(crate) assigner: &'a Assigner,
/// A struct used to construct (unique) definition statements.
pub(crate) definer: &'a Definer,
}
impl<'a> StaticSingleAssigner<'a> {
/// Initializes a new `StaticSingleAssigner` with an empty `RenameTable`.
pub(crate) fn new(node_builder: &'a NodeBuilder, symbol_table: &'a SymbolTable, assigner: &'a Assigner) -> Self {
Self { node_builder, symbol_table, rename_table: RenameTable::new(None), is_lhs: false, assigner }
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, definer }
}
/// 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`.
pub(crate) fn unique_simple_assign_statement(&mut self, expr: Expression) -> (Identifier, Statement) {
// 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.
let place = Identifier { name, span: Default::default(), id: self.node_builder.next_id() };
// 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.
let identifier = Identifier { name, span: Default::default(), id: self.node_builder.next_id() };