Change symbol table usages (next time will just make change in ST so don't have to change everything)

This commit is contained in:
evan-schott 2024-03-27 10:22:03 -07:00
parent 1dde26baec
commit 7a741dbde4
9 changed files with 59 additions and 90 deletions

View File

@ -14,31 +14,8 @@
// 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::CodeGenerator;
use leo_ast::{
AccessExpression,
ArrayAccess,
ArrayExpression,
AssociatedConstant,
AssociatedFunction,
BinaryExpression,
BinaryOperation,
CallExpression,
CastExpression,
ErrExpression,
Expression,
Identifier,
Literal,
MemberAccess,
ProgramScope,
StructExpression,
TernaryExpression,
TupleExpression,
Type,
UnaryExpression,
UnaryOperation,
UnitExpression,
};
use crate::{CodeGenerator, Location};
use leo_ast::{AccessExpression, ArrayAccess, ArrayExpression, AssociatedConstant, AssociatedFunction, BinaryExpression, BinaryOperation, CallExpression, CastExpression, ErrExpression, Expression, Identifier, Literal, LocatorExpression, MemberAccess, ProgramScope, StructExpression, TernaryExpression, TupleExpression, Type, UnaryExpression, UnaryOperation, UnitExpression};
use leo_span::sym;
use std::borrow::Borrow;
@ -60,6 +37,7 @@ impl<'a> CodeGenerator<'a> {
Expression::Err(expr) => self.visit_err(expr),
Expression::Identifier(expr) => self.visit_identifier(expr),
Expression::Literal(expr) => self.visit_value(expr),
Expression::Locator(expr) => self.visit_locator(expr),
Expression::Ternary(expr) => self.visit_ternary(expr),
Expression::Tuple(expr) => self.visit_tuple(expr),
Expression::Unary(expr) => self.visit_unary(expr),
@ -82,6 +60,10 @@ impl<'a> CodeGenerator<'a> {
(format!("{input}"), String::new())
}
fn visit_locator(&mut self, input: &'a LocatorExpression) -> (String, String) {
(format!("{input}"), String::new())
}
fn visit_binary(&mut self, input: &'a BinaryExpression) -> (String, String) {
let (left_operand, left_instructions) = self.visit_expression(&input.left);
let (right_operand, right_instructions) = self.visit_expression(&input.right);
@ -533,7 +515,7 @@ impl<'a> CodeGenerator<'a> {
// Initialize storage for the destination registers.
let mut destinations = Vec::new();
let return_type = &self.symbol_table.lookup_fn_symbol(main_program, function_name).unwrap().output_type;
let return_type = &self.symbol_table.lookup_fn_symbol(Location::new(Some(main_program), function_name)).unwrap().output_type;
match return_type {
Type::Unit => {} // Do nothing
Type::Tuple(tuple) => match tuple.length() {

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::Flattener;
use crate::{Flattener, Location};
use leo_ast::{
Expression,
@ -90,7 +90,7 @@ impl ExpressionReconstructor for Flattener<'_> {
Type::Composite(first_type) => {
// Get the struct definitions.
let first_type =
self.symbol_table.lookup_struct(first_type.program.unwrap(), first_type.id.name).unwrap();
self.symbol_table.lookup_struct(Location::new(first_type.program, first_type.id.name)).unwrap();
self.ternary_struct(first_type, &input.condition, &first, &second)
}
Type::Tuple(first_type) => self.ternary_tuple(first_type, &input.condition, &first, &second),

View File

@ -16,7 +16,7 @@
use leo_ast::*;
use crate::Unroller;
use crate::{Location, Unroller};
impl ProgramReconstructor for Unroller<'_> {
fn reconstruct_stub(&mut self, input: Stub) -> Stub {
@ -58,7 +58,7 @@ impl ProgramReconstructor for Unroller<'_> {
let function_index = self
.symbol_table
.borrow()
.lookup_fn_symbol(self.current_program.unwrap(), input.identifier.name)
.lookup_fn_symbol(Location::new(self.current_program, input.identifier.name))
.unwrap()
.id;
@ -77,7 +77,7 @@ impl ProgramReconstructor for Unroller<'_> {
let function_index = self
.symbol_table
.borrow()
.lookup_fn_symbol(self.current_program.unwrap(), function.identifier.name)
.lookup_fn_symbol(Location::new(self.current_program, function.identifier.name))
.unwrap()
.id;

View File

@ -19,7 +19,7 @@ use leo_ast::{Expression::Literal, Type::Integer, *};
use leo_errors::loop_unroller::LoopUnrollerError;
use leo_span::{Span, Symbol};
use crate::{unroller::Unroller, VariableSymbol, VariableType};
use crate::{Location, unroller::Unroller, VariableSymbol, VariableType};
impl StatementReconstructor for Unroller<'_> {
fn reconstruct_block(&mut self, input: Block) -> (Block, Self::AdditionalOutput) {
@ -60,7 +60,7 @@ impl StatementReconstructor for Unroller<'_> {
}
// Remove from symbol table
self.symbol_table.borrow_mut().remove_variable_from_current_scope(input.place.name);
self.symbol_table.borrow_mut().remove_variable_from_current_scope(Location::new(None,input.place.name));
(
Statement::Const(ConstDeclaration {
@ -77,7 +77,7 @@ impl StatementReconstructor for Unroller<'_> {
fn reconstruct_definition(&mut self, input: DefinitionStatement) -> (Statement, Self::AdditionalOutput) {
// Helper function to add variables to symbol table
let insert_variable = |symbol: Symbol, type_: Type, span: Span| {
if let Err(err) = self.symbol_table.borrow_mut().insert_variable(symbol, VariableSymbol {
if let Err(err) = self.symbol_table.borrow_mut().insert_variable(Location::new(None, symbol), VariableSymbol {
type_,
span,
declaration: VariableType::Mut,

View File

@ -14,31 +14,9 @@
// 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::StaticSingleAssigner;
use crate::{Location, StaticSingleAssigner};
use leo_ast::{
AccessExpression,
ArrayAccess,
ArrayExpression,
AssociatedFunction,
BinaryExpression,
CallExpression,
CastExpression,
Composite,
Expression,
ExpressionConsumer,
Identifier,
Literal,
MemberAccess,
Statement,
StructExpression,
StructVariableInitializer,
TernaryExpression,
TupleAccess,
TupleExpression,
UnaryExpression,
UnitExpression,
};
use leo_ast::{AccessExpression, ArrayAccess, ArrayExpression, AssociatedFunction, BinaryExpression, CallExpression, CastExpression, Composite, Expression, ExpressionConsumer, Identifier, Literal, LocatorExpression, MemberAccess, Statement, StructExpression, StructVariableInitializer, TernaryExpression, TupleAccess, TupleExpression, UnaryExpression, UnitExpression};
use leo_span::{sym, Symbol};
use indexmap::IndexMap;
@ -253,7 +231,7 @@ impl ExpressionConsumer for StaticSingleAssigner<'_> {
// Lookup the struct definition.
// Note that type checking guarantees that the correct struct definition exists.
let struct_definition: &Composite =
self.symbol_table.lookup_struct(self.program.unwrap(), input.name.name).unwrap();
self.symbol_table.lookup_struct(Location::new(self.program, input.name.name)).unwrap();
// Initialize the list of reordered members.
let mut reordered_members = Vec::with_capacity(members.len());
@ -317,6 +295,14 @@ impl ExpressionConsumer for StaticSingleAssigner<'_> {
let (place, statement) = self.unique_simple_assign_statement(Expression::Literal(input));
(Expression::Identifier(place), vec![statement])
}
/// Consumes and returns the locator expression without making any modifciations
fn consume_locator(&mut self, input: LocatorExpression) -> Self::Output {
// Construct and accumulate a new assignment statement for the locator expression.
let (place, statement) = self.unique_simple_assign_statement(Expression::Locator(input));
(Expression::Identifier(place), vec![statement])
}
/// Consumes a ternary expression, accumulating any statements that are generated.
fn consume_ternary(&mut self, input: TernaryExpression) -> Self::Output {

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::TypeChecker;
use crate::{Location, TypeChecker};
use leo_ast::*;
use leo_errors::{emitter::Handler, TypeCheckerError};
@ -53,6 +53,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
Expression::Err(err) => self.visit_err(err, additional),
Expression::Identifier(identifier) => self.visit_identifier(identifier, additional),
Expression::Literal(literal) => self.visit_literal(literal, additional),
Expression::Locator(locator) => panic!("aiya"), // TODO: self.visit_locator(locator, additional),
Expression::Ternary(ternary) => self.visit_ternary(ternary, additional),
Expression::Tuple(tuple) => self.visit_tuple(tuple, additional),
Expression::Unary(unary) => self.visit_unary(unary, additional),
@ -208,7 +209,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
let struct_ = self
.symbol_table
.borrow()
.lookup_struct(struct_.program.unwrap(), struct_.id.name)
.lookup_struct(Location::new(struct_.program, struct_.id.name))
.cloned();
if let Some(struct_) = struct_ {
// Check that `access.name` is a member of the struct.
@ -570,7 +571,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
Expression::Identifier(ident) => {
// Note: The function symbol lookup is performed outside of the `if let Some(func) ...` block to avoid a RefCell lifetime bug in Rust.
// Do not move it into the `if let Some(func) ...` block or it will keep `self.symbol_table_creation` alive for the entire block and will be very memory inefficient!
let func = self.symbol_table.borrow().lookup_fn_symbol(input.program.unwrap(), ident.name).cloned();
let func = self.symbol_table.borrow().lookup_fn_symbol(Location::new(input.program, ident.name)).cloned();
if let Some(func) = func {
// Check that the call is valid.
// Note that this unwrap is safe since we always set the variant before traversing the body of the function.
@ -649,7 +650,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
}
fn visit_struct_init(&mut self, input: &'a StructExpression, additional: &Self::AdditionalInput) -> Self::Output {
let struct_ = self.symbol_table.borrow().lookup_struct(self.program_name.unwrap(), input.name.name).cloned();
let struct_ = self.symbol_table.borrow().lookup_struct(Location::new(self.program_name, input.name.name)).cloned();
if let Some(struct_) = struct_ {
// Check struct type name.
let ret = self.check_expected_struct(&struct_, additional, input.name.span());
@ -695,7 +696,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
}
fn visit_identifier(&mut self, input: &'a Identifier, expected: &Self::AdditionalInput) -> Self::Output {
if let Some(var) = self.symbol_table.borrow().lookup_variable(input.name) {
if let Some(var) = self.symbol_table.borrow().lookup_variable(Location::new(None, input.name)) {
Some(self.assert_and_return_type(var.type_.clone(), expected, input.span()))
} else {
self.emit_err(TypeCheckerError::unknown_sym("variable", input.name, input.span()));

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::{DiGraphError, TypeChecker};
use crate::{DiGraphError, Location, TypeChecker};
use leo_ast::*;
use leo_errors::TypeCheckerError;
@ -70,7 +70,7 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
// Lookup function metadata in the symbol table.
// Note that this unwrap is safe since function metadata is stored in a prior pass.
let function_index =
self.symbol_table.borrow().lookup_fn_symbol(self.program_name.unwrap(), input.identifier.name).unwrap().id;
self.symbol_table.borrow().lookup_fn_symbol(Location::new(self.program_name, input.identifier.name)).unwrap().id;
// Enter the function's scope.
self.enter_scope(function_index);
@ -237,7 +237,7 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
Type::Tuple(_) => self.emit_err(TypeCheckerError::invalid_mapping_type("key", "tuple", input.span)),
Type::Composite(struct_type) => {
if let Some(struct_) =
self.symbol_table.borrow().lookup_struct(struct_type.program.unwrap(), struct_type.id.name)
self.symbol_table.borrow().lookup_struct(Location::new(struct_type.program, struct_type.id.name))
{
if struct_.is_record {
self.emit_err(TypeCheckerError::invalid_mapping_type("key", "record", input.span));
@ -256,7 +256,7 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
Type::Tuple(_) => self.emit_err(TypeCheckerError::invalid_mapping_type("value", "tuple", input.span)),
Type::Composite(struct_type) => {
if let Some(struct_) =
self.symbol_table.borrow().lookup_struct(struct_type.program.unwrap(), struct_type.id.name)
self.symbol_table.borrow().lookup_struct(Location::new(struct_type.program, struct_type.id.name))
{
if struct_.is_record {
self.emit_err(TypeCheckerError::invalid_mapping_type("value", "record", input.span));
@ -284,7 +284,7 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
let function_index = self
.symbol_table
.borrow()
.lookup_fn_symbol(self.program_name.unwrap(), function.identifier.name)
.lookup_fn_symbol(Location::new(self.program_name, function.identifier.name))
.unwrap()
.id;

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::{TypeChecker, VariableSymbol, VariableType};
use crate::{Location, TypeChecker, VariableSymbol, VariableType};
use itertools::Itertools;
use leo_ast::*;
@ -68,7 +68,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
}
};
let var_type = if let Some(var) = self.symbol_table.borrow_mut().lookup_variable(var_name.name) {
let var_type = if let Some(var) = self.symbol_table.borrow_mut().lookup_variable(Location::new(None, var_name.name)) {
match &var.declaration {
VariableType::Const => self.emit_err(TypeCheckerError::cannot_assign_to_const_var(var_name, var.span)),
VariableType::Input(Mode::Constant) => {
@ -192,7 +192,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
self.visit_expression(&input.value, &Some(input.type_.clone()));
// Add constants to symbol table so that any references to them in later statements will pass TC
if let Err(err) = self.symbol_table.borrow_mut().insert_variable(input.place.name, VariableSymbol {
if let Err(err) = self.symbol_table.borrow_mut().insert_variable(Location::new(None, input.place.name), VariableSymbol {
type_: input.type_.clone(),
span: input.place.span,
declaration: VariableType::Const,
@ -240,7 +240,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
// TODO: Dedup with unrolling pass.
// Helper to insert the variables into the symbol table.
let insert_variable = |symbol: Symbol, type_: Type, span: Span| {
if let Err(err) = self.symbol_table.borrow_mut().insert_variable(symbol, VariableSymbol {
if let Err(err) = self.symbol_table.borrow_mut().insert_variable(Location::new(None, symbol), VariableSymbol {
type_,
span,
declaration: VariableType::Mut,
@ -308,7 +308,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
let scope_index = self.create_child_scope();
// Add the loop variable to the scope of the loop body.
if let Err(err) = self.symbol_table.borrow_mut().insert_variable(input.variable.name, VariableSymbol {
if let Err(err) = self.symbol_table.borrow_mut().insert_variable(Location::new(None, input.variable.name), VariableSymbol {
type_: input.type_.clone(),
span: input.span(),
declaration: VariableType::Const,
@ -347,7 +347,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
}
}
Expression::Identifier(id) => {
if let Some(var) = self.symbol_table.borrow().lookup_variable(id.name) {
if let Some(var) = self.symbol_table.borrow().lookup_variable(Location::new(None, id.name)) {
if VariableType::Const != var.declaration {
self.emit_err(TypeCheckerError::loop_bound_must_be_literal_or_const(id.span));
}
@ -367,7 +367,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
}
}
Expression::Identifier(id) => {
if let Some(var) = self.symbol_table.borrow().lookup_variable(id.name) {
if let Some(var) = self.symbol_table.borrow().lookup_variable(Location::new(None, id.name)) {
if VariableType::Const != var.declaration {
self.emit_err(TypeCheckerError::loop_bound_must_be_literal_or_const(id.span));
}
@ -381,7 +381,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
// We can safely unwrap all self.parent instances because
// statements should always have some parent block
let parent = self.function.unwrap();
let return_type = &self.symbol_table.borrow().lookup_fn_symbol(self.program_name.unwrap(), parent).map(|f| {
let return_type = &self.symbol_table.borrow().lookup_fn_symbol(Location::new(self.program_name, parent)).map(|f| {
match self.is_finalize {
// TODO: Check this.
// Note that this `unwrap()` is safe since we checked that the function has a finalize block.
@ -423,7 +423,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
let finalize = self
.symbol_table
.borrow()
.lookup_fn_symbol(self.program_name.unwrap(), self.function.unwrap())
.lookup_fn_symbol(Location::new(self.program_name, self.function.unwrap()))
.unwrap()
.finalize
.clone();

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::{CallGraph, StructGraph, SymbolTable, TypeTable, VariableSymbol, VariableType};
use crate::{CallGraph, Location, StructGraph, SymbolTable, TypeTable, VariableSymbol, VariableType};
use leo_ast::{
Composite,
@ -1064,7 +1064,7 @@ impl<'a> TypeChecker<'a> {
pub(crate) fn check_duplicate_struct(&self, name: Symbol, program_1: Symbol, program_2: Symbol) -> bool {
// Make sure that both structs have been defined already.
let st = self.symbol_table.borrow();
let (struct_1, struct_2) = match (st.lookup_struct(program_1, name), st.lookup_struct(program_2, name)) {
let (struct_1, struct_2) = match (st.lookup_struct(Location::new(Some(program_1), name)), st.lookup_struct(Location::new(Some(program_2), name))) {
(Some(struct_1), Some(struct_2)) => (struct_1, struct_2),
_ => return false,
};
@ -1109,7 +1109,7 @@ impl<'a> TypeChecker<'a> {
if self
.symbol_table
.borrow()
.lookup_struct(struct_.program.unwrap(), struct_.id.name)
.lookup_struct(Location::new(struct_.program, struct_.id.name))
.map_or(false, |struct_| struct_.is_record) =>
{
self.emit_err(TypeCheckerError::struct_or_record_cannot_contain_record(parent, struct_.id.name, span))
@ -1134,7 +1134,7 @@ impl<'a> TypeChecker<'a> {
}
// Check that the named composite type has been defined.
Type::Composite(struct_)
if self.symbol_table.borrow().lookup_struct(struct_.program.unwrap(), struct_.id.name).is_none() =>
if self.symbol_table.borrow().lookup_struct(Location::new(struct_.program, struct_.id.name)).is_none() =>
{
is_valid = false;
self.emit_err(TypeCheckerError::undefined_type(struct_.id.name, span));
@ -1168,7 +1168,7 @@ impl<'a> TypeChecker<'a> {
Type::Composite(struct_type) => {
// Look up the type.
if let Some(struct_) =
self.symbol_table.borrow().lookup_struct(struct_type.program.unwrap(), struct_type.id.name)
self.symbol_table.borrow().lookup_struct(Location::new(struct_type.program, struct_type.id.name))
{
// Check that the type is not a record.
if struct_.is_record {
@ -1227,7 +1227,7 @@ impl<'a> TypeChecker<'a> {
// If the function is not a transition function, then it cannot have a record as input
if let Type::Composite(struct_) = input_var.type_() {
if let Some(val) = self.symbol_table.borrow().lookup_struct(struct_.program.unwrap(), struct_.id.name) {
if let Some(val) = self.symbol_table.borrow().lookup_struct(Location::new(struct_.program, struct_.id.name)) {
if val.is_record && !matches!(function.variant, Variant::Transition) {
self.emit_err(TypeCheckerError::function_cannot_input_or_output_a_record(input_var.span()));
}
@ -1237,7 +1237,7 @@ impl<'a> TypeChecker<'a> {
// Add non-stub inputs to the symbol table.
if !self.is_stub {
if let Err(err) =
self.symbol_table.borrow_mut().insert_variable(input_var.identifier().name, VariableSymbol {
self.symbol_table.borrow_mut().insert_variable(Location::new(None, input_var.identifier().name), VariableSymbol {
type_: input_var.type_(),
span: input_var.identifier().span(),
declaration: VariableType::Input(input_var.mode()),
@ -1270,7 +1270,7 @@ impl<'a> TypeChecker<'a> {
&& self
.symbol_table
.borrow()
.lookup_struct(struct_.program.unwrap(), struct_.id.name)
.lookup_struct(Location::new(struct_.program, struct_.id.name))
.unwrap()
.is_record
{
@ -1322,7 +1322,7 @@ impl<'a> TypeChecker<'a> {
if self
.symbol_table
.borrow()
.lookup_struct(struct_.program.unwrap(), struct_.id.name)
.lookup_struct(Location::new(struct_.program, struct_.id.name))
.unwrap()
.is_record
{
@ -1336,7 +1336,7 @@ impl<'a> TypeChecker<'a> {
// Add non-stub inputs to the symbol table.
if !self.is_stub {
if let Err(err) =
self.symbol_table.borrow_mut().insert_variable(input_var.identifier().name, VariableSymbol {
self.symbol_table.borrow_mut().insert_variable(Location::new(None, input_var.identifier().name), VariableSymbol {
type_: input_var.type_(),
span: input_var.identifier().span(),
declaration: VariableType::Input(input_var.mode()),
@ -1371,7 +1371,7 @@ impl<'a> TypeChecker<'a> {
if self
.symbol_table
.borrow()
.lookup_struct(struct_.program.unwrap(), struct_.id.name)
.lookup_struct(Location::new(struct_.program, struct_.id.name))
.unwrap()
.is_record
{
@ -1393,7 +1393,7 @@ impl<'a> TypeChecker<'a> {
/// Emits an error if the type corresponds to an external struct.
pub(crate) fn assert_internal_struct(&self, composite: &CompositeType, span: Span) {
let st = self.symbol_table.borrow();
match st.lookup_struct(composite.program.unwrap(), composite.id.name) {
match st.lookup_struct(Location::new(composite.program, composite.id.name)) {
None => self.emit_err(TypeCheckerError::undefined_type(composite.id, span)),
Some(composite_def) => {
if !composite_def.is_record && composite_def.external.unwrap() != self.program_name.unwrap() {