Skip to content

Commit

Permalink
constant time lookups
Browse files Browse the repository at this point in the history
  • Loading branch information
evan-schott committed Oct 3, 2023
1 parent dde39bd commit 2942c9a
Show file tree
Hide file tree
Showing 7 changed files with 35 additions and 13 deletions.
2 changes: 1 addition & 1 deletion compiler/parser/src/parser/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()?;
Expand Down
12 changes: 10 additions & 2 deletions compiler/passes/src/code_generation/visit_program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,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(),
}
Expand Down
2 changes: 2 additions & 0 deletions compiler/passes/src/function_inlining/function_inliner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
23 changes: 15 additions & 8 deletions compiler/passes/src/function_inlining/inline_program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
5 changes: 5 additions & 0 deletions tests/expectations/compiler/definition/tuple_def_fail.out
Original file line number Diff line number Diff line change
@@ -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"
2 changes: 1 addition & 1 deletion tests/tests/compiler/definition/tuple_def_fail.leo
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
namespace: Compile
expectation: Pass
expectation: Fail
*/

program test.aleo {
Expand Down

0 comments on commit 2942c9a

Please sign in to comment.