From 75f3647879e016873a10ef36447c5ff3b64cadaa Mon Sep 17 00:00:00 2001
From: evan-schott <53463459+evan-schott@users.noreply.github.com>
Date: Wed, 27 Mar 2024 10:24:01 -0700
Subject: [PATCH] Passing ST serialization test
---
.../common/symbol_table/function_symbol.rs | 4 +-
.../src/common/symbol_table/location.rs | 20 ++-
.../passes/src/common/symbol_table/mod.rs | 127 +++++++++---------
.../src/symbol_table_creation/creator.rs | 24 +++-
4 files changed, 95 insertions(+), 80 deletions(-)
diff --git a/compiler/passes/src/common/symbol_table/function_symbol.rs b/compiler/passes/src/common/symbol_table/function_symbol.rs
index 1d3c7307f7..ec347ca788 100644
--- a/compiler/passes/src/common/symbol_table/function_symbol.rs
+++ b/compiler/passes/src/common/symbol_table/function_symbol.rs
@@ -22,7 +22,7 @@ use serde::{Deserialize, Serialize};
use crate::SymbolTable;
/// Metadata associated with the finalize block.
-#[derive(Debug, Clone, Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct FinalizeData {
/// The inputs to the finalize block.
pub(crate) input: Vec,
@@ -31,7 +31,7 @@ pub struct FinalizeData {
}
/// An entry for a function in the symbol table.
-#[derive(Clone, Debug, Serialize, Deserialize)]
+#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct FunctionSymbol {
/// The index associated with the scope in the parent symbol table.
pub(crate) id: usize,
diff --git a/compiler/passes/src/common/symbol_table/location.rs b/compiler/passes/src/common/symbol_table/location.rs
index 719c044d98..bda2edfca2 100644
--- a/compiler/passes/src/common/symbol_table/location.rs
+++ b/compiler/passes/src/common/symbol_table/location.rs
@@ -20,13 +20,13 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
// Create custom struct to wrap (Symbol, Symbol) so that it can be serialized and deserialized.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Location {
- pub program: Symbol,
+ pub program: Option,
pub name: Symbol,
}
impl Location {
// Create new Location instance.
- pub fn new(program: Symbol, name: Symbol) -> Location {
+ pub fn new(program: Option, name: Symbol) -> Location {
Location { program, name }
}
}
@@ -36,7 +36,11 @@ impl Serialize for Location {
where
S: Serializer,
{
- serializer.serialize_str(&format!("{}/{}", self.program, self.name))
+ let condensed_str = match self.program {
+ Some(program) => format!("{}/{}", program, self.name),
+ None => format!("{}", self.name),
+ };
+ serializer.serialize_str(&condensed_str)
}
}
@@ -46,9 +50,13 @@ impl<'de> Deserialize<'de> for Location {
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
- let mut parts = s.split('/');
- let program = Symbol::intern(parts.next().unwrap());
- let name = Symbol::intern(parts.next().unwrap());
+ let mut parts: Vec<&str> = s.split('/').collect();
+ let program = if parts.len() == 1 {
+ None
+ } else {
+ Some(Symbol::intern(parts.remove(0)))
+ };
+ let name = Symbol::intern(parts.get(0).unwrap());
Ok(Location::new(program, name))
}
}
diff --git a/compiler/passes/src/common/symbol_table/mod.rs b/compiler/passes/src/common/symbol_table/mod.rs
index 9335a4684b..ae24c0b471 100644
--- a/compiler/passes/src/common/symbol_table/mod.rs
+++ b/compiler/passes/src/common/symbol_table/mod.rs
@@ -36,7 +36,7 @@ use serde_json;
// TODO (@d0cd) Consider a safe interface for the symbol table.
// TODO (@d0cd) Cleanup API
-#[derive(Clone, Debug, Default, Serialize, Deserialize)]
+#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
pub struct SymbolTable {
/// The parent scope if it exists.
/// For example, the parent scope of a then-block is the scope containing the associated ConditionalStatement.
@@ -49,7 +49,7 @@ pub struct SymbolTable {
pub structs: IndexMap,
/// The variables defined in a scope.
/// This field is populated as necessary.
- pub(crate) variables: IndexMap,
+ pub(crate) variables: IndexMap,
/// The index of the current scope.
pub(crate) scope_index: usize,
/// The sub-scopes of this scope.
@@ -59,21 +59,22 @@ pub struct SymbolTable {
impl SymbolTable {
/// Recursively checks if the symbol table contains an entry for the given symbol.
/// Leo does not allow any variable shadowing or overlap between different symbols.
- pub fn check_shadowing(&self, program: Option, symbol: Symbol, span: Span) -> Result<()> {
- if let Some(program) = program {
- if self.functions.contains_key(&Location::new(program, symbol)) {
- return Err(AstError::shadowed_function(symbol, span).into());
- } else if let Some(existing) = self.structs.get(&Location::new(program, symbol)) {
+ pub fn check_shadowing(&self, location: &Location, span: Span) -> Result<()> {
+ if let Some(_) = location.program {
+ if self.functions.contains_key(location) {
+ return Err(AstError::shadowed_function(location.name, span).into());
+ } else if let Some(existing) = self.structs.get(location) {
return match existing.is_record {
- true => Err(AstError::shadowed_record(symbol, span).into()),
- false => Err(AstError::shadowed_struct(symbol, span).into()),
+ true => Err(AstError::shadowed_record(location.name, span).into()),
+ false => Err(AstError::shadowed_struct(location.name, span).into()),
};
}
- }
- if self.variables.contains_key(&symbol) {
- Err(AstError::shadowed_variable(symbol, span).into())
- } else if let Some(parent) = self.parent.as_ref() {
- parent.check_shadowing(program, symbol, span)
+ else if self.variables.contains_key(location) {
+ return Err(AstError::shadowed_variable(location.name, span).into())
+ }
+ }
+ if let Some(parent) = self.parent.as_ref() {
+ return parent.check_shadowing(location, span)
} else {
Ok(())
}
@@ -88,19 +89,19 @@ impl SymbolTable {
}
/// Inserts a function into the symbol table.
- pub fn insert_fn(&mut self, program: Symbol, symbol: Symbol, insert: &Function) -> Result<()> {
+ pub fn insert_fn(&mut self, location: Location, insert: &Function) -> Result<()> {
let id = self.scope_index();
- self.check_shadowing(Some(program), symbol, insert.span)?;
- self.functions.insert(Location::new(program, symbol), Self::new_function_symbol(id, insert));
+ self.check_shadowing(&location, insert.span)?;
+ self.functions.insert(location, Self::new_function_symbol(id, insert));
self.scopes.push(Default::default());
Ok(())
}
/// Inserts a struct into the symbol table.
- pub fn insert_struct(&mut self, program: Symbol, symbol: Symbol, insert: &Composite) -> Result<()> {
- match self.check_shadowing(Some(program), symbol, insert.span) {
+ pub fn insert_struct(&mut self, location: Location, insert: &Composite) -> Result<()> {
+ match self.check_shadowing(&location, insert.span) {
Ok(_) => {
- self.structs.insert(Location::new(program, symbol), insert.clone());
+ self.structs.insert(location, insert.clone());
Ok(())
}
Err(e) => Err(e),
@@ -108,15 +109,15 @@ impl SymbolTable {
}
/// Inserts a variable into the symbol table.
- pub fn insert_variable(&mut self, symbol: Symbol, insert: VariableSymbol) -> Result<()> {
- self.check_shadowing(None, symbol, insert.span)?;
- self.variables.insert(symbol, insert);
+ pub fn insert_variable(&mut self, location: Location, insert: VariableSymbol) -> Result<()> {
+ self.check_shadowing(&location, insert.span)?;
+ self.variables.insert(location, insert);
Ok(())
}
/// Removes a variable from the symbol table.
- pub fn remove_variable_from_current_scope(&mut self, symbol: Symbol) {
- self.variables.remove(&symbol);
+ pub fn remove_variable_from_current_scope(&mut self, location: Location) {
+ self.variables.remove(&location);
}
/// Creates a new scope for the block and stores it in the symbol table.
@@ -126,58 +127,33 @@ impl SymbolTable {
}
/// Attempts to lookup a function in the symbol table.
- pub fn lookup_fn_symbol(&self, program: Symbol, symbol: Symbol) -> Option<&FunctionSymbol> {
- if let Some(func) = self.functions.get(&Location::new(program, symbol)) {
+ pub fn lookup_fn_symbol(&self, location: Location) -> Option<&FunctionSymbol> {
+ if let Some(func) = self.functions.get(&location) {
Some(func)
} else if let Some(parent) = self.parent.as_ref() {
- parent.lookup_fn_symbol(program, symbol)
+ parent.lookup_fn_symbol(location)
} else {
None
}
}
/// Attempts to lookup a struct in the symbol table.
- pub fn lookup_struct(&self, program: Symbol, symbol: Symbol) -> Option<&Composite> {
- if let Some(struct_) = self.structs.get(&Location::new(program, symbol)) {
+ pub fn lookup_struct(&self, location: Location) -> Option<&Composite> {
+ if let Some(struct_) = self.structs.get(&location) {
Some(struct_)
} else if let Some(parent) = self.parent.as_ref() {
- parent.lookup_struct(program, symbol)
+ parent.lookup_struct(location)
} else {
None
}
}
/// Attempts to lookup a variable in the symbol table.
- pub fn lookup_variable(&self, symbol: Symbol) -> Option<&VariableSymbol> {
- if let Some(var) = self.variables.get(&symbol) {
+ pub fn lookup_variable(&self, location: Location) -> Option<&VariableSymbol> {
+ if let Some(var) = self.variables.get(&location) {
Some(var)
} else if let Some(parent) = self.parent.as_ref() {
- parent.lookup_variable(symbol)
- } else {
- None
- }
- }
-
- /// Returns true if the variable exists in the local scope
- pub fn variable_in_local_scope(&self, symbol: Symbol) -> bool {
- self.variables.contains_key(&symbol)
- }
-
- /// Returns true if the variable exists in any parent scope
- pub fn variable_in_parent_scope(&self, symbol: Symbol) -> bool {
- if let Some(parent) = self.parent.as_ref() {
- if parent.variables.contains_key(&symbol) { true } else { parent.variable_in_parent_scope(symbol) }
- } else {
- false
- }
- }
-
- /// Returns a mutable reference to the `VariableSymbol` if it exists in the symbol table.
- pub fn lookup_variable_mut(&mut self, symbol: Symbol) -> Option<&mut VariableSymbol> {
- if let Some(var) = self.variables.get_mut(&symbol) {
- Some(var)
- } else if let Some(parent) = self.parent.as_mut() {
- parent.lookup_variable_mut(symbol)
+ parent.lookup_variable(location)
} else {
None
}
@@ -251,12 +227,10 @@ mod tests {
use leo_ast::{Identifier, Type, Variant};
use leo_span::symbol::create_session_if_not_set_then;
#[test]
- #[ignore]
fn serialization_test() {
create_session_if_not_set_then(|_| {
let mut symbol_table = SymbolTable::default();
- let program = Symbol::intern("credits");
- let function = Symbol::intern("transfer_public");
+ let func_loc = Location::new(Some(Symbol::intern("credits")), Symbol::intern("transfer_public"));
let insert = Function {
annotations: Vec::new(),
id: 0,
@@ -269,11 +243,34 @@ mod tests {
output: vec![],
block: Default::default(),
};
- symbol_table.insert_fn(program, function, &insert).unwrap();
+ symbol_table.insert_fn(func_loc, &insert).unwrap();
+ symbol_table.insert_variable(
+ Location::new(Some(Symbol::intern("credits")), Symbol::intern("accounts")),
+ VariableSymbol {
+ type_: Type::Address,
+ span: Default::default(),
+ declaration: VariableType::Const,
+ }).unwrap();
+ symbol_table.insert_struct(
+ Location::new(Some(Symbol::intern("credits")), Symbol::intern("token")),
+ &Composite {
+ is_record: false,
+ span: Default::default(),
+ id: 0,
+ identifier: Identifier::new(Symbol::intern("token"), Default::default()),
+ members: Vec::new(),
+ external: None,
+ }).unwrap();
+ symbol_table.insert_variable(
+ Location::new(None, Symbol::intern("foo")),
+ VariableSymbol {
+ type_: Type::Address,
+ span: Default::default(),
+ declaration: VariableType::Const,
+ }).unwrap();
let json = symbol_table.to_json_string().unwrap();
- dbg!(json.clone());
let deserialized = SymbolTable::from_json_string(&json).unwrap();
- dbg!(deserialized);
+ assert_eq!(symbol_table, deserialized);
});
}
}
diff --git a/compiler/passes/src/symbol_table_creation/creator.rs b/compiler/passes/src/symbol_table_creation/creator.rs
index ac4375cbfd..ff3c092479 100644
--- a/compiler/passes/src/symbol_table_creation/creator.rs
+++ b/compiler/passes/src/symbol_table_creation/creator.rs
@@ -18,7 +18,7 @@ use leo_ast::*;
use leo_errors::emitter::Handler;
use leo_span::Symbol;
-use crate::{SymbolTable, VariableSymbol, VariableType};
+use crate::{Location, SymbolTable, VariableSymbol, VariableType};
/// A compiler pass during which the `SymbolTable` is created.
/// Note that this pass only creates the initial entries for functions, structs, and records.
@@ -30,11 +30,13 @@ pub struct SymbolTableCreator<'a> {
handler: &'a Handler,
/// The current program name.
program_name: Option,
+ /// Whether or not traversing stub.
+ is_stub: bool,
}
impl<'a> SymbolTableCreator<'a> {
pub fn new(handler: &'a Handler) -> Self {
- Self { symbol_table: Default::default(), handler, program_name: None }
+ Self { symbol_table: Default::default(), handler, program_name: None, is_stub: false }
}
}
@@ -49,6 +51,7 @@ impl<'a> ProgramVisitor<'a> for SymbolTableCreator<'a> {
fn visit_program_scope(&mut self, input: &'a ProgramScope) {
// Set current program name
self.program_name = Some(input.program_id.name.name);
+ self.is_stub = false;
// Visit the program scope
input.structs.iter().for_each(|(_, c)| (self.visit_struct(c)));
@@ -62,17 +65,23 @@ impl<'a> ProgramVisitor<'a> for SymbolTableCreator<'a> {
}
fn visit_struct(&mut self, input: &'a Composite) {
- if let Err(err) = self.symbol_table.insert_struct(self.program_name.unwrap(), input.name(), input) {
+ if let Err(err) = self.symbol_table.insert_struct(Location::new(self.program_name, input.name()), input) {
self.handler.emit_err(err);
}
}
fn visit_mapping(&mut self, input: &'a Mapping) {
+ // Check if mapping is external.
+ let program = match self.is_stub {
+ true => self.program_name,
+ false => None,
+ };
// Add the variable associated with the mapping to the symbol table.
- if let Err(err) = self.symbol_table.insert_variable(input.identifier.name, VariableSymbol {
+ if let Err(err) = self.symbol_table.insert_variable(Location::new(program, input.identifier.name), VariableSymbol {
type_: Type::Mapping(MappingType {
key: Box::new(input.key_type.clone()),
value: Box::new(input.value_type.clone()),
+ program: self.program_name.unwrap(),
}),
span: input.span,
declaration: VariableType::Mut,
@@ -82,12 +91,13 @@ impl<'a> ProgramVisitor<'a> for SymbolTableCreator<'a> {
}
fn visit_function(&mut self, input: &'a Function) {
- if let Err(err) = self.symbol_table.insert_fn(self.program_name.unwrap(), input.name(), input) {
+ if let Err(err) = self.symbol_table.insert_fn(Location::new(self.program_name, input.name()), input) {
self.handler.emit_err(err);
}
}
fn visit_stub(&mut self, input: &'a Stub) {
+ self.is_stub = true;
self.program_name = Some(input.stub_id.name.name);
input.functions.iter().for_each(|(_, c)| (self.visit_function_stub(c)));
input.structs.iter().for_each(|(_, c)| (self.visit_struct_stub(c)));
@@ -95,14 +105,14 @@ impl<'a> ProgramVisitor<'a> for SymbolTableCreator<'a> {
fn visit_function_stub(&mut self, input: &'a FunctionStub) {
if let Err(err) =
- self.symbol_table.insert_fn(self.program_name.unwrap(), input.name(), &Function::from(input.clone()))
+ self.symbol_table.insert_fn(Location::new(self.program_name, input.name()), &Function::from(input.clone()))
{
self.handler.emit_err(err);
}
}
fn visit_struct_stub(&mut self, input: &'a Composite) {
- if let Err(err) = self.symbol_table.insert_struct(self.program_name.unwrap(), input.name(), input) {
+ if let Err(err) = self.symbol_table.insert_struct(Location::new(self.program_name, input.name()), input) {
self.handler.emit_err(err);
}
}