This commit is contained in:
Pranav Gaddamadugu 2023-10-10 17:48:59 -04:00 committed by Pranav Gaddamadugu
parent 7e5a6e9755
commit d1a5283513
4 changed files with 32 additions and 53 deletions

View File

@ -147,10 +147,10 @@ impl ExpressionReconstructor for Flattener<'_> {
(Expression::Identifier(first), Expression::Identifier(second))
if self.structs.contains_key(&first.name) && self.structs.contains_key(&second.name) =>
{
let first_struct = self.symbol_table.lookup_struct(*self.structs.get(&first.name).unwrap()).unwrap();
let second_struct = self.symbol_table.lookup_struct(*self.structs.get(&second.name).unwrap()).unwrap();
let first_struct = self.structs.get(&first.name).unwrap().clone();
let second_struct = self.structs.get(&second.name).unwrap();
// Note that type checking guarantees that both expressions have the same same type. This is a sanity check.
assert_eq!(first_struct, second_struct);
assert_eq!(&first_struct, second_struct);
self.ternary_struct(first_struct, &input.condition, &first, &second)
}

View File

@ -28,7 +28,9 @@ impl ProgramReconstructor for Flattener<'_> {
self.structs = Default::default();
for input in &finalize.input {
if let Type::Identifier(struct_name) = input.type_() {
self.structs.insert(input.identifier().name, struct_name.name);
// Note that this unwrap is safe since type checking guarantees that the struct exists.
let struct_ = self.symbol_table.lookup_struct(struct_name.name).unwrap().clone();
self.structs.insert(input.identifier().name, struct_);
}
}
// Flatten the finalize block.
@ -55,7 +57,9 @@ impl ProgramReconstructor for Flattener<'_> {
self.structs = Default::default();
for input in &function.input {
if let Type::Identifier(struct_name) = input.type_() {
self.structs.insert(input.identifier().name, struct_name.name);
// Note that this unwrap is safe since type checking guarantees that the struct exists.
let struct_ = self.symbol_table.lookup_struct(struct_name.name).unwrap().clone();
self.structs.insert(input.identifier().name, struct_);
}
}

View File

@ -191,7 +191,9 @@ impl StatementReconstructor for Flattener<'_> {
// If the output type is a struct, add it to `self.structs`.
if let Type::Identifier(struct_name) = type_ {
self.structs.insert(identifier.name, struct_name.name);
// Note that this unwrap is safe since type checking guarantees that the struct exists.
let struct_ = self.symbol_table.lookup_struct(struct_name.name).unwrap().clone();
self.structs.insert(identifier.name, struct_);
}
Expression::Identifier(identifier)
@ -217,7 +219,9 @@ impl StatementReconstructor for Flattener<'_> {
type_ => {
// If the function returns a struct, add it to `self.structs`.
if let Type::Identifier(struct_name) = type_ {
self.structs.insert(lhs_identifier.name, struct_name.name);
// Note that this unwrap is safe since type checking guarantees that the struct exists.
let struct_ = self.symbol_table.lookup_struct(struct_name.name).unwrap().clone();
self.structs.insert(lhs_identifier.name, struct_);
};
(
Statement::Assign(Box::new(AssignStatement {
@ -266,7 +270,9 @@ impl StatementReconstructor for Flattener<'_> {
};
// If the value type is a struct, add it to `self.structs`.
if let Type::Identifier(struct_name) = value_type {
self.structs.insert(lhs_identifier.name, struct_name.name);
// Note that this unwrap is safe since type checking guarantees that the struct exists.
let struct_ = self.symbol_table.lookup_struct(struct_name.name).unwrap().clone();
self.structs.insert(lhs_identifier.name, struct_);
}
// Reconstruct the assignment.
(
@ -280,8 +286,7 @@ 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.simple_assign_statement(identifier, expression), 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)) => {
@ -306,7 +311,9 @@ impl StatementReconstructor for Flattener<'_> {
};
// If the output type is a struct, add it to `self.structs`.
if let Type::Identifier(struct_name) = type_ {
self.structs.insert(identifier.name, struct_name.name);
// Note that this unwrap is safe since type checking guarantees that the struct exists.
let struct_ = self.symbol_table.lookup_struct(struct_name.name).unwrap().clone();
self.structs.insert(identifier.name, struct_);
}
});

View File

@ -57,7 +57,7 @@ pub struct Flattener<'a> {
/// A struct used to construct (unique) assignment statements.
pub(crate) assigner: &'a Assigner,
/// The set of variables that are structs.
pub(crate) structs: IndexMap<Symbol, Symbol>,
pub(crate) structs: IndexMap<Symbol, Struct>,
/// A stack of condition `Expression`s visited up to the current point in the AST.
pub(crate) condition_stack: Vec<Expression>,
/// A list containing tuples of guards and expressions associated `ReturnStatement`s.
@ -167,41 +167,8 @@ impl<'a> Flattener<'a> {
}
}
/// Looks up the name of the struct associated with an identifier or access expression, if it exists.
pub(crate) fn lookup_struct_symbol(&self, expression: &Expression) -> Option<Symbol> {
match expression {
Expression::Identifier(identifier) => self.structs.get(&identifier.name).copied(),
Expression::Access(AccessExpression::Member(access)) => {
// The inner expression of an access expression is either an identifier or another access expression.
let name = self.lookup_struct_symbol(&access.inner).unwrap();
let struct_ = self.symbol_table.lookup_struct(name).unwrap();
let Member { type_, .. } =
struct_.members.iter().find(|member| member.name() == access.name.name).unwrap();
match type_ {
Type::Identifier(identifier) => Some(identifier.name),
_ => None,
}
}
_ => None,
}
}
/// Updates `self.structs` for new assignment statements.
/// Expects the left hand side of the assignment to be an identifier.
pub(crate) fn update_structs(&mut self, lhs: &Identifier, rhs: &Expression) {
match rhs {
Expression::Struct(rhs) => {
self.structs.insert(lhs.name, rhs.name.name);
}
// If the rhs of the assignment is an identifier that is a struct, add it to `self.structs`.
Expression::Identifier(rhs) if self.structs.contains_key(&rhs.name) => {
// Note that this unwrap is safe because we just checked that the key exists.
self.structs.insert(lhs.name, *self.structs.get(&rhs.name).unwrap());
}
// Otherwise, do nothing.
_ => (),
}
}
/// Gets the type of the expression, if it's being tracked.
pub(crate) fn get_type(&self, expression: &Expression) -> Option<Type> {}
/// A wrapper around `assigner.unique_simple_assign_statement` that updates `self.structs`.
// TODO (@d0cd) Update to check for tuples and arrays
@ -211,7 +178,7 @@ impl<'a> Flattener<'a> {
// 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.simple_assign_statement(place, expr);
match &statement {
Statement::Assign(assign) => {
@ -222,10 +189,11 @@ impl<'a> Flattener<'a> {
(place, statement)
}
/// A wrapper around `assigner.simple_assign_statement` that updates `self.structs`.
/// A wrapper around `assigner.simple_assign_statement` that tracks the type of the lhs.
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())
let statement = self.assigner.simple_assign_statement(lhs, rhs, self.node_builder.next_id());
self.update_types(&statement);
statement
}
/// Folds a list of return statements into a single return statement and adds the produced statements to the block.
@ -380,7 +348,7 @@ impl<'a> Flattener<'a> {
pub(crate) fn ternary_struct(
&mut self,
struct_: &Struct,
struct_: Struct,
condition: &Expression,
first: &Identifier,
second: &Identifier,
@ -447,7 +415,7 @@ impl<'a> Flattener<'a> {
let (identifier, statement) = self.unique_simple_assign_statement(expr);
// Mark the lhs of the assignment as a struct.
self.structs.insert(identifier.name, struct_.identifier.name);
self.structs.insert(identifier.name, struct_);
statements.push(statement);