Support AST changes in compile passes

This commit is contained in:
Pranav Gaddamadugu 2022-10-05 10:38:35 -07:00
parent 224cf18544
commit 8f2a6fdb27
9 changed files with 81 additions and 51 deletions

View File

@ -129,6 +129,13 @@ pub trait MappingConsumer {
fn consume_mapping(&mut self, input: Mapping) -> Self::Output;
}
/// A Consumer trait for program scopes in the AST.
pub trait ProgramScopeConsumer {
type Output;
fn consume_program_scope(&mut self, input: ProgramScope) -> Self::Output;
}
/// A Consumer trait for the program represented by the AST.
pub trait ProgramConsumer {
type Output;

View File

@ -312,14 +312,28 @@ pub trait StatementReconstructor: ExpressionReconstructor {
pub trait ProgramReconstructor: StatementReconstructor {
fn reconstruct_program(&mut self, input: Program) -> Program {
Program {
name: input.name,
network: input.network,
expected_input: input.expected_input,
imports: input
.imports
.into_iter()
.map(|(id, import)| (id, self.reconstruct_import(import)))
.collect(),
program_scopes: input
.program_scopes
.into_iter()
.map(|(id, scope)| (id, self.reconstruct_program_scope(scope)))
.collect(),
}
}
fn reconstruct_program_scope(&mut self, input: ProgramScope) -> ProgramScope {
ProgramScope {
name: input.name,
network: input.network,
structs: input
.structs
.into_iter()
.map(|(i, c)| (i, self.reconstruct_struct(c)))
.collect(),
mappings: input
.mappings
.into_iter()
@ -330,11 +344,6 @@ pub trait ProgramReconstructor: StatementReconstructor {
.into_iter()
.map(|(i, f)| (i, self.reconstruct_function(f)))
.collect(),
structs: input
.structs
.into_iter()
.map(|(i, c)| (i, self.reconstruct_struct(c)))
.collect(),
}
}

View File

@ -195,6 +195,13 @@ pub trait ProgramVisitor<'a>: StatementVisitor<'a> {
fn visit_program(&mut self, input: &'a Program) {
input.imports.values().for_each(|import| self.visit_import(import));
input
.program_scopes
.values()
.for_each(|scope| self.visit_program_scope(scope));
}
fn visit_program_scope(&mut self, input: &'a ProgramScope) {
input.structs.values().for_each(|function| self.visit_struct(function));
input.mappings.values().for_each(|mapping| self.visit_mapping(mapping));

View File

@ -19,7 +19,7 @@
pub mod program_scope;
pub use program_scope::*;
use crate::{Identifier};
use crate::Identifier;
use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
@ -39,7 +39,7 @@ impl fmt::Display for Program {
for (id, _import) in self.imports.iter() {
writeln!(f, "import {}.leo;", id)?;
}
for (_, program_scope) in self.structs.iter() {
for (_, program_scope) in self.program_scopes.iter() {
program_scope.fmt(f)?;
writeln!(f,)?;
}

View File

@ -17,7 +17,7 @@
//! The compiler for Leo programs.
//!
//! The [`Compiler`] type compiles Leo programs into R1CS circuits.
use leo_ast::{Node, Program};
use leo_ast::Program;
pub use leo_ast::{Ast, InputAst};
use leo_errors::emitter::Handler;
use leo_errors::{CompilerError, Result};
@ -97,15 +97,7 @@ impl<'a> Compiler<'a> {
// Use the parser to construct the abstract syntax tree (ast).
self.ast = leo_parser::parse_ast(self.handler, &prg_sf.src, prg_sf.start_pos)?;
// Check that the name associated with the program scope matches file name.
if with_session_globals(|s| self.ast.ast.name.name.as_str(s, |s| s != &self.program_name)) {
return Err(CompilerError::program_name_should_match_file_name(
&self.ast.ast.name,
&self.program_name,
self.ast.ast.name.span(),
)
.into());
}
// TODO: Check that the program name matches the file name.
if self.output_options.initial_ast {
self.write_ast_to_json("initial_ast.json")?;

View File

@ -120,7 +120,7 @@ impl ParserContext<'_> {
let network = self.expect_identifier()?;
// Parse `{`.
let _open = self.expect(&Token::OpenBrace)?;
let _open = self.expect(&Token::LeftCurly)?;
// Parse the body of the program scope.
let mut functions = IndexMap::new();
@ -142,13 +142,13 @@ impl ParserContext<'_> {
functions.insert(id, function);
}
Token::Circuit => return Err(ParserError::circuit_is_deprecated(self.token.span).into()),
Token::CloseBrace => break,
Token::RightCurly => break,
_ => return Err(Self::unexpected_item(&self.token).into()),
}
}
// Parse `}`.
let _close = self.expect(&Token::CloseBrace)?;
let _close = self.expect(&Token::RightCurly)?;
Ok(ProgramScope {
name,

View File

@ -16,7 +16,7 @@
use crate::CodeGenerator;
use leo_ast::{functions, CallType, Function, Identifier, Mapping, Mode, Program, Struct, Type};
use leo_ast::{functions, CallType, Function, Identifier, Mapping, Mode, Program, ProgramScope, Struct, Type};
use indexmap::IndexMap;
use itertools::Itertools;
@ -42,16 +42,24 @@ impl<'a> CodeGenerator<'a> {
program_string.push('\n');
}
// Retrieve the program scope.
// Note that type checking guarantees that there is exactly one program scope.
let program_scope: &ProgramScope = input.program_scopes.values().next().unwrap();
// Print the program id.
writeln!(program_string, "program {}.{};", input.name, input.network)
.expect("Failed to write program id to string.");
writeln!(
program_string,
"program {}.{};",
program_scope.name, program_scope.network
)
.expect("Failed to write program id to string.");
// Newline separator.
program_string.push('\n');
// Visit each `Struct` or `Record` in the Leo AST and produce a Aleo interface instruction.
program_string.push_str(
&input
&program_scope
.structs
.values()
.map(|struct_| self.visit_struct_or_record(struct_))
@ -63,7 +71,7 @@ impl<'a> CodeGenerator<'a> {
// Visit each mapping in the Leo AST and produce an Aleo mapping declaration.
program_string.push_str(
&input
&program_scope
.mappings
.values()
.map(|mapping| self.visit_mapping(mapping))
@ -75,7 +83,7 @@ impl<'a> CodeGenerator<'a> {
let mut functions = String::new();
// Visit each `Function` in the Leo AST and produce Aleo instructions.
input.functions.values().for_each(|function| {
program_scope.functions.values().for_each(|function| {
self.is_transition_function = matches!(function.call_type, CallType::Transition);
let function_string = self.visit_function(function);

View File

@ -16,7 +16,10 @@
use crate::StaticSingleAssigner;
use leo_ast::{Block, Finalize, Function, FunctionConsumer, Program, ProgramConsumer, StatementConsumer};
use leo_ast::{
Block, Finalize, Function, FunctionConsumer, Program, ProgramConsumer, ProgramScope, ProgramScopeConsumer,
StatementConsumer,
};
impl FunctionConsumer for StaticSingleAssigner {
type Output = Function;
@ -84,27 +87,39 @@ impl FunctionConsumer for StaticSingleAssigner {
}
}
impl ProgramConsumer for StaticSingleAssigner {
type Output = Program;
impl ProgramScopeConsumer for StaticSingleAssigner {
type Output = ProgramScope;
fn consume_program(&mut self, input: Program) -> Self::Output {
Program {
fn consume_program_scope(&mut self, input: ProgramScope) -> Self::Output {
ProgramScope {
name: input.name,
network: input.network,
expected_input: input.expected_input,
// TODO: Do inputs need to be processed? They are not processed in the existing compiler.
imports: input
.imports
.into_iter()
.map(|(name, import)| (name, self.consume_program(import)))
.collect(),
structs: input.structs,
mappings: input.mappings,
functions: input
.functions
.into_iter()
.map(|(i, f)| (i, self.consume_function(f)))
.collect(),
structs: input.structs,
mappings: input.mappings,
}
}
}
impl ProgramConsumer for StaticSingleAssigner {
type Output = Program;
fn consume_program(&mut self, input: Program) -> Self::Output {
Program {
imports: input
.imports
.into_iter()
.map(|(name, import)| (name, self.consume_program(import)))
.collect(),
program_scopes: input
.program_scopes
.into_iter()
.map(|(name, scope)| (name, self.consume_program_scope(scope)))
.collect(),
}
}
}

View File

@ -120,14 +120,6 @@ create_messages!(
help: None,
}
/// For when the parser encountered a deprecated `test function`.
@formatted
test_function {
args: (),
msg: "\"test function...\" is deprecated. Did you mean @test annotation?",
help: None,
}
/// When more input was expected but not found.
@backtraced
lexer_empty_input {