Update AST to include FunctionStub and Stub

This commit is contained in:
evan-schott 2023-10-06 13:55:37 -07:00
parent 72cf2e7517
commit cf7baa0132
7 changed files with 244 additions and 2 deletions

View File

@ -59,6 +59,10 @@ pub mod types;
pub use self::types::*; pub use self::types::*;
pub mod value; pub mod value;
pub mod stub;
pub use self::stub::*;
pub use self::value::*; pub use self::value::*;
pub use common::node::*; pub use common::node::*;

View File

@ -417,6 +417,7 @@ pub trait ProgramReconstructor: StatementReconstructor {
.into_iter() .into_iter()
.map(|(id, import)| (id, (self.reconstruct_import(import.0), import.1))) .map(|(id, import)| (id, (self.reconstruct_import(import.0), import.1)))
.collect(), .collect(),
stubs: input.stubs,
program_scopes: input program_scopes: input
.program_scopes .program_scopes
.into_iter() .into_iter()

View File

@ -222,7 +222,7 @@ pub trait StatementVisitor<'a>: ExpressionVisitor<'a> {
pub trait ProgramVisitor<'a>: StatementVisitor<'a> { pub trait ProgramVisitor<'a>: StatementVisitor<'a> {
fn visit_program(&mut self, input: &'a Program) { fn visit_program(&mut self, input: &'a Program) {
input.imports.values().for_each(|import| self.visit_import(&import.0)); input.imports.values().for_each(|import| self.visit_import(&import.0));
input.stubs.values().for_each(|stub| self.visit_stub(stub));
input.program_scopes.values().for_each(|scope| self.visit_program_scope(scope)); input.program_scopes.values().for_each(|scope| self.visit_program_scope(scope));
} }
@ -236,6 +236,8 @@ pub trait ProgramVisitor<'a>: StatementVisitor<'a> {
input.consts.iter().for_each(|(_, c)| (self.visit_const(c))); input.consts.iter().for_each(|(_, c)| (self.visit_const(c)));
} }
fn visit_stub(&mut self, _input: &'a Stub) {}
fn visit_import(&mut self, input: &'a Program) { fn visit_import(&mut self, input: &'a Program) {
self.visit_program(input) self.visit_program(input)
} }

View File

@ -24,6 +24,7 @@ pub use program_scope::*;
use leo_span::{Span, Symbol}; use leo_span::{Span, Symbol};
use crate::Stub;
use indexmap::IndexMap; use indexmap::IndexMap;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::fmt; use std::fmt;
@ -33,6 +34,8 @@ use std::fmt;
pub struct Program { pub struct Program {
/// A map from import names to import definitions. /// A map from import names to import definitions.
pub imports: IndexMap<Symbol, (Program, Span)>, pub imports: IndexMap<Symbol, (Program, Span)>,
/// A map from program stub names to program stub scopes.
pub stubs: IndexMap<Symbol, Stub>,
/// A map from program names to program scopes. /// A map from program names to program scopes.
pub program_scopes: IndexMap<Symbol, ProgramScope>, pub program_scopes: IndexMap<Symbol, ProgramScope>,
} }
@ -42,6 +45,10 @@ impl fmt::Display for Program {
for (id, _import) in self.imports.iter() { for (id, _import) in self.imports.iter() {
writeln!(f, "import {id}.leo;")?; writeln!(f, "import {id}.leo;")?;
} }
for (_, stub) in self.stubs.iter() {
stub.fmt(f)?;
writeln!(f,)?;
}
for (_, program_scope) in self.program_scopes.iter() { for (_, program_scope) in self.program_scopes.iter() {
program_scope.fmt(f)?; program_scope.fmt(f)?;
writeln!(f,)?; writeln!(f,)?;
@ -53,6 +60,6 @@ impl fmt::Display for Program {
impl Default for Program { impl Default for Program {
/// Constructs an empty program node. /// Constructs an empty program node.
fn default() -> Self { fn default() -> Self {
Self { imports: IndexMap::new(), program_scopes: IndexMap::new() } Self { imports: IndexMap::new(), stubs: IndexMap::new(), program_scopes: IndexMap::new() }
} }
} }

View File

@ -0,0 +1,152 @@
// Copyright (C) 2019-2023 Aleo Systems Inc.
// This file is part of the Leo library.
// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{Annotation, Block, Finalize, Function, Identifier, Input, Node, NodeID, Output, Tuple, Type, Variant};
use leo_span::{sym, Span, Symbol};
use serde::{Deserialize, Serialize};
use std::fmt;
/// A function stub definition.
#[derive(Clone, Serialize, Deserialize)]
pub struct FunctionStub {
/// Annotations on the function.
pub annotations: Vec<Annotation>,
/// Is this function a transition, inlined, or a regular function?.
pub variant: Variant,
/// The function identifier, e.g., `foo` in `function foo(...) { ... }`.
pub identifier: Identifier,
/// The function's input parameters.
pub input: Vec<Input>,
/// The function's output declarations.
pub output: Vec<Output>,
/// The function's output type.
pub output_type: Type,
/// The body of the function.
pub block: Block,
/// An optional finalize block
pub finalize: Option<Finalize>,
/// The entire span of the function definition.
pub span: Span,
/// The ID of the node.
pub id: NodeID,
}
impl PartialEq for FunctionStub {
fn eq(&self, other: &Self) -> bool {
self.identifier == other.identifier
}
}
impl Eq for FunctionStub {}
impl FunctionStub {
/// Initialize a new function.
#[allow(clippy::too_many_arguments)]
pub fn new(
annotations: Vec<Annotation>,
variant: Variant,
identifier: Identifier,
input: Vec<Input>,
output: Vec<Output>,
block: Block,
finalize: Option<Finalize>,
span: Span,
id: NodeID,
) -> Self {
// Determine the output type of the function
let get_output_type = |output: &Output| match &output {
Output::Internal(output) => output.type_.clone(),
Output::External(output) => output.type_(),
};
let output_type = match output.len() {
0 => Type::Unit,
1 => get_output_type(&output[0]),
_ => Type::Tuple(Tuple(output.iter().map(get_output_type).collect())),
};
FunctionStub { annotations, variant, identifier, input, output, output_type, block, finalize, span, id }
}
/// Returns function name.
pub fn name(&self) -> Symbol {
self.identifier.name
}
/// Returns `true` if the function name is `main`.
pub fn is_main(&self) -> bool {
self.name() == sym::main
}
///
/// Private formatting method used for optimizing [fmt::Debug] and [fmt::Display] implementations.
///
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.variant {
Variant::Inline => write!(f, "inline ")?,
Variant::Standard => write!(f, "function ")?,
Variant::Transition => write!(f, "transition ")?,
}
write!(f, "{}", self.identifier)?;
let parameters = self.input.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(",");
let returns = match self.output.len() {
0 => "()".to_string(),
1 => self.output[0].to_string(),
_ => self.output.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(","),
};
write!(f, "({parameters}) -> {returns} {}", self.block)?;
if let Some(finalize) = &self.finalize {
let parameters = finalize.input.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(",");
write!(f, " finalize ({parameters}) {}", finalize.block)
} else {
Ok(())
}
}
}
impl From<Function> for FunctionStub {
fn from(function: Function) -> Self {
Self {
annotations: function.annotations,
variant: function.variant,
identifier: function.identifier,
input: function.input,
output: function.output,
output_type: function.output_type,
block: function.block,
finalize: function.finalize,
span: function.span,
id: function.id,
}
}
}
impl fmt::Debug for FunctionStub {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.format(f)
}
}
impl fmt::Display for FunctionStub {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.format(f)
}
}
crate::simple_node_impl!(FunctionStub);

View File

@ -0,0 +1,75 @@
// Copyright (C) 2019-2023 Aleo Systems Inc.
// This file is part of the Leo library.
// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
//! A stub contains function templates as well as definitions for mappings, structs, records, and constants.
pub mod function_stub;
pub use function_stub::*;
use crate::{ConstDeclaration, Mapping, ProgramId, ProgramScope, Struct};
use leo_span::{Span, Symbol};
use serde::{Deserialize, Serialize};
use std::fmt;
/// Stores the Leo stub abstract syntax tree.
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct Stub {
/// The stub id
pub stub_id: ProgramId,
/// A vector of const definitions
pub consts: Vec<(Symbol, ConstDeclaration)>,
/// A vector of struct definitions.
pub structs: Vec<(Symbol, Struct)>,
/// A vector of mapping definitions.
pub mappings: Vec<(Symbol, Mapping)>,
/// A vector of function stub definitions.
pub functions: Vec<(Symbol, FunctionStub)>,
/// The span associated with the stub.
pub span: Span,
}
impl From<ProgramScope> for Stub {
fn from(program_scope: ProgramScope) -> Self {
Self {
stub_id: program_scope.program_id,
consts: program_scope.consts,
structs: program_scope.structs,
mappings: program_scope.mappings,
functions: program_scope
.functions
.into_iter()
.map(|(symbol, function)| (symbol, FunctionStub::from(function)))
.collect(),
span: program_scope.span,
}
}
}
impl fmt::Display for Stub {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "stub {} {{", self.stub_id)?;
for (_, struct_) in self.structs.iter() {
writeln!(f, " {struct_}")?;
}
for (_, mapping) in self.mappings.iter() {
writeln!(f, " {mapping}")?;
}
for (_, function) in self.functions.iter() {
writeln!(f, " {function}")?;
}
Ok(())
}
}

View File

@ -151,6 +151,7 @@ impl ProgramConsumer for StaticSingleAssigner<'_> {
.into_iter() .into_iter()
.map(|(name, (import, span))| (name, (self.consume_program(import), span))) .map(|(name, (import, span))| (name, (self.consume_program(import), span)))
.collect(), .collect(),
stubs: input.stubs,
program_scopes: input program_scopes: input
.program_scopes .program_scopes
.into_iter() .into_iter()