mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-12-24 02:31:44 +03:00
Implement post-order codegen for structs and records
This commit is contained in:
parent
a4d76c644a
commit
899c12d85a
@ -203,9 +203,9 @@ impl<'a> Compiler<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Runs the compiler stages.
|
/// Runs the compiler stages.
|
||||||
pub fn compiler_stages(&mut self) -> Result<SymbolTable> {
|
pub fn compiler_stages(&mut self) -> Result<(SymbolTable, StructGraph)> {
|
||||||
let st = self.symbol_table_pass()?;
|
let st = self.symbol_table_pass()?;
|
||||||
let (st, _struct_graph) = self.type_checker_pass(st)?;
|
let (st, struct_graph) = self.type_checker_pass(st)?;
|
||||||
|
|
||||||
// TODO: Make this pass optional.
|
// TODO: Make this pass optional.
|
||||||
let st = self.loop_unrolling_pass(st)?;
|
let st = self.loop_unrolling_pass(st)?;
|
||||||
@ -215,16 +215,16 @@ impl<'a> Compiler<'a> {
|
|||||||
|
|
||||||
self.flattening_pass(&st, assigner)?;
|
self.flattening_pass(&st, assigner)?;
|
||||||
|
|
||||||
Ok(st)
|
Ok((st, struct_graph))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a compiled Leo program and prints the resulting bytecode.
|
/// Returns a compiled Leo program and prints the resulting bytecode.
|
||||||
// TODO: Remove when code generation is ready to be integrated into the compiler.
|
// TODO: Remove when code generation is ready to be integrated into the compiler.
|
||||||
pub fn compile_and_generate_instructions(&mut self) -> Result<(SymbolTable, String)> {
|
pub fn compile_and_generate_instructions(&mut self) -> Result<(SymbolTable, String)> {
|
||||||
self.parse_program()?;
|
self.parse_program()?;
|
||||||
let symbol_table = self.compiler_stages()?;
|
let (symbol_table, struct_graph) = self.compiler_stages()?;
|
||||||
|
|
||||||
let bytecode = CodeGenerator::do_pass((&self.ast, &symbol_table))?;
|
let bytecode = CodeGenerator::do_pass((&self.ast, &symbol_table, &struct_graph))?;
|
||||||
|
|
||||||
Ok((symbol_table, bytecode))
|
Ok((symbol_table, bytecode))
|
||||||
}
|
}
|
||||||
@ -232,7 +232,7 @@ impl<'a> Compiler<'a> {
|
|||||||
/// Returns a compiled Leo program.
|
/// Returns a compiled Leo program.
|
||||||
pub fn compile(&mut self) -> Result<SymbolTable> {
|
pub fn compile(&mut self) -> Result<SymbolTable> {
|
||||||
self.parse_program()?;
|
self.parse_program()?;
|
||||||
self.compiler_stages()
|
self.compiler_stages().map(|(st, _)| st)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes the AST to a JSON file.
|
/// Writes the AST to a JSON file.
|
||||||
|
@ -194,14 +194,14 @@ fn temp_dir() -> PathBuf {
|
|||||||
|
|
||||||
fn compile_and_process<'a>(parsed: &'a mut Compiler<'a>) -> Result<String, LeoError> {
|
fn compile_and_process<'a>(parsed: &'a mut Compiler<'a>) -> Result<String, LeoError> {
|
||||||
let st = parsed.symbol_table_pass()?;
|
let st = parsed.symbol_table_pass()?;
|
||||||
let (st, _struct_graph) = parsed.type_checker_pass(st)?;
|
let (st, struct_graph) = parsed.type_checker_pass(st)?;
|
||||||
let st = parsed.loop_unrolling_pass(st)?;
|
let st = parsed.loop_unrolling_pass(st)?;
|
||||||
let assigner = parsed.static_single_assignment_pass(&st)?;
|
let assigner = parsed.static_single_assignment_pass(&st)?;
|
||||||
|
|
||||||
parsed.flattening_pass(&st, assigner)?;
|
parsed.flattening_pass(&st, assigner)?;
|
||||||
|
|
||||||
// Compile Leo program to bytecode.
|
// Compile Leo program to bytecode.
|
||||||
let bytecode = CodeGenerator::do_pass((&parsed.ast, &st))?;
|
let bytecode = CodeGenerator::do_pass((&parsed.ast, &st, &struct_graph))?;
|
||||||
|
|
||||||
Ok(bytecode)
|
Ok(bytecode)
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::SymbolTable;
|
use crate::SymbolTable;
|
||||||
|
use crate::StructGraph;
|
||||||
|
|
||||||
use leo_ast::Function;
|
use leo_ast::Function;
|
||||||
use leo_span::Symbol;
|
use leo_span::Symbol;
|
||||||
@ -24,6 +25,8 @@ use indexmap::IndexMap;
|
|||||||
pub struct CodeGenerator<'a> {
|
pub struct CodeGenerator<'a> {
|
||||||
/// The symbol table for the program.
|
/// The symbol table for the program.
|
||||||
pub(crate) symbol_table: &'a SymbolTable,
|
pub(crate) symbol_table: &'a SymbolTable,
|
||||||
|
/// The struct dependency graph for the program.
|
||||||
|
pub(crate) struct_graph: &'a StructGraph,
|
||||||
/// A counter to track the next available register.
|
/// A counter to track the next available register.
|
||||||
pub(crate) next_register: u64,
|
pub(crate) next_register: u64,
|
||||||
/// Reference to the current function.
|
/// Reference to the current function.
|
||||||
@ -42,10 +45,11 @@ pub struct CodeGenerator<'a> {
|
|||||||
|
|
||||||
impl<'a> CodeGenerator<'a> {
|
impl<'a> CodeGenerator<'a> {
|
||||||
/// Initializes a new `CodeGenerator`.
|
/// Initializes a new `CodeGenerator`.
|
||||||
pub fn new(symbol_table: &'a SymbolTable) -> Self {
|
pub fn new(symbol_table: &'a SymbolTable, struct_graph: &'a StructGraph) -> Self {
|
||||||
// Initialize variable mapping.
|
// Initialize variable mapping.
|
||||||
Self {
|
Self {
|
||||||
symbol_table,
|
symbol_table,
|
||||||
|
struct_graph,
|
||||||
next_register: 0,
|
next_register: 0,
|
||||||
current_function: None,
|
current_function: None,
|
||||||
variable_mapping: IndexMap::new(),
|
variable_mapping: IndexMap::new(),
|
||||||
|
@ -26,16 +26,17 @@ mod visit_statements;
|
|||||||
mod visit_type;
|
mod visit_type;
|
||||||
|
|
||||||
use crate::{Pass, SymbolTable};
|
use crate::{Pass, SymbolTable};
|
||||||
|
use crate::{StructGraph};
|
||||||
|
|
||||||
use leo_ast::Ast;
|
use leo_ast::Ast;
|
||||||
use leo_errors::Result;
|
use leo_errors::Result;
|
||||||
|
|
||||||
impl<'a> Pass for CodeGenerator<'a> {
|
impl<'a> Pass for CodeGenerator<'a> {
|
||||||
type Input = (&'a Ast, &'a SymbolTable);
|
type Input = (&'a Ast, &'a SymbolTable, &'a StructGraph);
|
||||||
type Output = Result<String>;
|
type Output = Result<String>;
|
||||||
|
|
||||||
fn do_pass((ast, symbol_table): Self::Input) -> Self::Output {
|
fn do_pass((ast, symbol_table, struct_graph): Self::Input) -> Self::Output {
|
||||||
let mut generator = Self::new(symbol_table);
|
let mut generator = Self::new(symbol_table, struct_graph);
|
||||||
let bytecode = generator.visit_program(ast.as_repr());
|
let bytecode = generator.visit_program(ast.as_repr());
|
||||||
|
|
||||||
Ok(bytecode)
|
Ok(bytecode)
|
||||||
|
@ -16,11 +16,11 @@
|
|||||||
|
|
||||||
use crate::CodeGenerator;
|
use crate::CodeGenerator;
|
||||||
|
|
||||||
use leo_ast::{functions, CallType, Function, Identifier, Mapping, Mode, Program, ProgramScope, Struct, Type};
|
use leo_ast::{functions, CallType, Function, Mapping, Mode, Program, ProgramScope, Struct, Type};
|
||||||
|
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use leo_span::sym;
|
use leo_span::{sym, Symbol};
|
||||||
use std::fmt::Write as _;
|
use std::fmt::Write as _;
|
||||||
|
|
||||||
impl<'a> CodeGenerator<'a> {
|
impl<'a> CodeGenerator<'a> {
|
||||||
@ -53,12 +53,19 @@ impl<'a> CodeGenerator<'a> {
|
|||||||
// Newline separator.
|
// Newline separator.
|
||||||
program_string.push('\n');
|
program_string.push('\n');
|
||||||
|
|
||||||
// Visit each `Struct` or `Record` in the Leo AST and produce a Aleo struct.
|
// Get the post-order ordering of the composite data types.
|
||||||
|
// 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();
|
||||||
|
|
||||||
|
// Visit each `Struct` or `Record` in the post-ordering and produce an Aleo struct or record.
|
||||||
program_string.push_str(
|
program_string.push_str(
|
||||||
&program_scope
|
&order
|
||||||
.structs
|
.into_iter()
|
||||||
.values()
|
.map(|name| {
|
||||||
.map(|struct_| self.visit_struct_or_record(struct_))
|
// Note that this unwrap is safe since type checking guarantees that all structs are declared.
|
||||||
|
let struct_ = program_scope.structs.get(&name).unwrap();
|
||||||
|
self.visit_struct_or_record(struct_)
|
||||||
|
})
|
||||||
.join("\n"),
|
.join("\n"),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -104,7 +111,7 @@ impl<'a> CodeGenerator<'a> {
|
|||||||
program_string
|
program_string
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_import(&mut self, import_name: &'a Identifier, import_program: &'a Program) -> String {
|
fn visit_import(&mut self, import_name: &'a Symbol, import_program: &'a Program) -> String {
|
||||||
// Load symbols into composite mapping.
|
// Load symbols into composite mapping.
|
||||||
let _import_program_string = self.visit_program(import_program);
|
let _import_program_string = self.visit_program(import_program);
|
||||||
// todo: We do not need the import program string because we generate instructions for imports separately during leo build.
|
// todo: We do not need the import program string because we generate instructions for imports separately during leo build.
|
||||||
|
@ -41,6 +41,7 @@ enum BenchMode {
|
|||||||
Ssa,
|
Ssa,
|
||||||
/// Benchmarks flattening.
|
/// Benchmarks flattening.
|
||||||
Flatten,
|
Flatten,
|
||||||
|
// TODO: Benchmark code generation
|
||||||
/// Benchmarks all the above stages.
|
/// Benchmarks all the above stages.
|
||||||
Full,
|
Full,
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user