constant time lookups

This commit is contained in:
evan-schott 2023-10-03 16:11:17 -07:00
parent 909289c83c
commit c37eeaae03
7 changed files with 35 additions and 13 deletions

View File

@ -147,7 +147,7 @@ impl ParserContext<'_> {
match &self.token.token {
Token::Const => {
let declaration = self.parse_const_declaration_statement()?;
consts.push((Symbol::intern(&declaration.place.to_string()), definition));
consts.push((Symbol::intern(&declaration.place.to_string()), declaration));
}
Token::Struct | Token::Record => {
let (id, struct_) = self.parse_struct()?;

View File

@ -59,14 +59,22 @@ impl<'a> CodeGenerator<'a> {
// Note that the unwrap is safe since type checking guarantees that the struct dependency graph is acyclic.
let order = self.struct_graph.post_order().unwrap();
// Create a mapping of symbols to references of structs so can perform constant-time lookups.
let structs_map: IndexMap<Symbol, &Struct> = program_scope.structs.iter().map(|(name, struct_)| {
(
*name,
struct_
)
}).collect();
// Visit each `Struct` or `Record` in the post-ordering and produce an Aleo struct or record.
program_string.push_str(
&order
.into_iter()
.map(|name| {
match program_scope.structs.iter().find(|(identifier, _)| *identifier == name) {
match structs_map.get(&name) {
// If the struct is found, it is a local struct.
Some((_, struct_)) => self.visit_struct_or_record(struct_),
Some(struct_) => self.visit_struct_or_record(*struct_),
// If the struct is not found, it is an imported struct.
None => String::new(),
}

View File

@ -19,6 +19,8 @@ use crate::{Assigner, AssignmentRenamer, CallGraph};
use leo_ast::{Function, NodeBuilder};
use leo_span::Symbol;
use indexmap::IndexMap;
pub struct FunctionInliner<'a> {
/// A counter used to create unique NodeIDs.
pub(crate) node_builder: &'a NodeBuilder,

View File

@ -15,8 +15,10 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::FunctionInliner;
use indexmap::{IndexMap, IndexSet};
use leo_ast::{ProgramReconstructor, ProgramScope};
use leo_ast::{Function, ProgramReconstructor, ProgramScope};
use leo_span::Symbol;
impl ProgramReconstructor for FunctionInliner<'_> {
fn reconstruct_program_scope(&mut self, mut input: ProgramScope) -> ProgramScope {
@ -25,25 +27,30 @@ impl ProgramReconstructor for FunctionInliner<'_> {
// Note that the unwrap is safe since type checking guarantees that the call graph is acyclic.
let order = self.call_graph.post_order().unwrap();
// Construct map to provide faster lookup of functions
let function_map: IndexMap<Symbol, Function> = input.functions.clone().into_iter().collect();
// Construct set to keep track of the remaining functions that still need to be processed.
let mut function_set: IndexSet<Symbol> = function_map.keys().cloned().collect();
// Reconstruct and accumulate each of the functions in post-order.
for function_name in order.into_iter() {
// None: If `function_name` is not in `input.functions`, then it must be an external function.
// TODO: Check that this is indeed an external function. Requires a redesign of the symbol table.
if let Some(pos) = input.functions.iter().position(|(symbol, _)| *symbol == function_name) {
let (_, function) = input.functions.remove(pos);
if let Some(function) = function_map.get(&function_name) {
function_set.remove(&function_name);
// Reconstruct the function.
let reconstructed_function = self.reconstruct_function(function);
let reconstructed_function = self.reconstruct_function(function.clone());
// Add the reconstructed function to the mapping.
self.reconstructed_functions.insert(function_name, reconstructed_function);
}
}
// Check that `input.functions` is empty.
// This is a sanity check to ensure that functions in the program scope have been processed.
assert!(input.functions.is_empty(), "All functions in the program scope should have been processed.");
assert!(function_set.is_empty(), "All functions in the program scope should have been processed.");
input.functions.clear();
// Note that this intentionally clears `self.reconstructed_functions` for the next program scope.
let functions = core::mem::take(&mut self.reconstructed_functions).into_iter().map(|(symbol, function)| (*symbol, function.clone())).collect();
let functions = core::mem::take(&mut self.reconstructed_functions).into_iter().collect();
ProgramScope {
program_id: input.program_id,

View File

@ -2,4 +2,4 @@
namespace: Compile
expectation: Fail
outputs:
- "Error [ETYC0372082]: Expected a tuple with 2 elements, found one with 3 elements\n --> compiler-test:5:13\n |\n 5 | let (a,b,c): (u8,u8) = (2u8,3u8);\n | ^^^^^^^\nError [ETYC0372082]: Expected a tuple with 3 elements, found one with 2 elements\n --> compiler-test:6:13\n |\n 6 | let (d,e): (u8,u8,u8) = (1u8,2u8,3u8);\n | ^^^^^\n"
- "Error [ETYC0372082]: Expected a tuple with 2 elements, found one with 3 elements\n --> compiler-test:5:13\n |\n 5 | let (a,b,c): (u8,u8) = (2u8,3u8);\n | ^^^^^^^\nError [ETYC0372082]: Expected a tuple with 3 elements, found one with 2 elements\n --> compiler-test:6:13\n |\n 6 | let (d,e): (u8,u8,u8) = (1u8,2u8,3u8);\n | ^^^^^\nError [ETYC0372003]: Expected type `(u8,u8,u8)` but type `u8` was found\n --> compiler-test:7:36\n |\n 7 | let (g,h,i): (u8,u8,u8) = (1u8);\n | ^^^\n"

View File

@ -0,0 +1,5 @@
---
namespace: Compile
expectation: Fail
outputs:
- "Error [ETYC0372061]: Tuples on the left-hand side of a `DefinitionStatement` can only contain identifiers.\n --> compiler-test:5:14\n |\n 5 | let (1u8+1u8,1u8+1u8): (u8,u8) = (1u8,2u8);\n | ^^^^^^^\nError [ETYC0372061]: Tuples on the left-hand side of a `DefinitionStatement` can only contain identifiers.\n --> compiler-test:5:22\n |\n 5 | let (1u8+1u8,1u8+1u8): (u8,u8) = (1u8,2u8);\n | ^^^^^^^\n"

View File

@ -1,6 +1,6 @@
/*
namespace: Compile
expectation: Pass
expectation: Fail
*/
program test.aleo {