mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-09-11 13:56:58 +03:00
WIP
This commit is contained in:
parent
b8a41e483d
commit
4778fe6405
@ -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.
|
||||||
|
@ -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.
|
||||||
|
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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| {
|
||||||
|
@ -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() };
|
||||||
|
Loading…
Reference in New Issue
Block a user