mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-11-23 15:15:47 +03:00
Passing ST serialization test
This commit is contained in:
parent
7a741dbde4
commit
75f3647879
@ -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<Input>,
|
||||
@ -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,
|
||||
|
@ -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<Symbol>,
|
||||
pub name: Symbol,
|
||||
}
|
||||
|
||||
impl Location {
|
||||
// Create new Location instance.
|
||||
pub fn new(program: Symbol, name: Symbol) -> Location {
|
||||
pub fn new(program: Option<Symbol>, 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))
|
||||
}
|
||||
}
|
||||
|
@ -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<Location, Composite>,
|
||||
/// The variables defined in a scope.
|
||||
/// This field is populated as necessary.
|
||||
pub(crate) variables: IndexMap<Symbol, VariableSymbol>,
|
||||
pub(crate) variables: IndexMap<Location, VariableSymbol>,
|
||||
/// 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: 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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -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<Symbol>,
|
||||
/// 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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user