Skip to content

Commit

Permalink
Merge pull request #2606 from AleoHQ/feat/global-constants
Browse files Browse the repository at this point in the history
Feat/global constants
  • Loading branch information
d0cd authored Oct 5, 2023
2 parents 5262e0c + e55035c commit bd9714a
Show file tree
Hide file tree
Showing 744 changed files with 6,628 additions and 5,336 deletions.
3 changes: 3 additions & 0 deletions compiler/ast/src/passes/consumer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ pub trait StatementConsumer {
Statement::Block(stmt) => self.consume_block(stmt),
Statement::Conditional(stmt) => self.consume_conditional(stmt),
Statement::Console(stmt) => self.consume_console(stmt),
Statement::Const(stmt) => self.consume_const(stmt),
Statement::Definition(stmt) => self.consume_definition(stmt),
Statement::Expression(stmt) => self.consume_expression_statement(stmt),
Statement::Iteration(stmt) => self.consume_iteration(*stmt),
Expand All @@ -95,6 +96,8 @@ pub trait StatementConsumer {

fn consume_console(&mut self, input: ConsoleStatement) -> Self::Output;

fn consume_const(&mut self, input: ConstDeclaration) -> Self::Output;

fn consume_definition(&mut self, input: DefinitionStatement) -> Self::Output;

fn consume_expression_statement(&mut self, input: ExpressionStatement) -> Self::Output;
Expand Down
22 changes: 22 additions & 0 deletions compiler/ast/src/passes/reconstructor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ pub trait StatementReconstructor: ExpressionReconstructor {
}
Statement::Conditional(stmt) => self.reconstruct_conditional(stmt),
Statement::Console(stmt) => self.reconstruct_console(stmt),
Statement::Const(stmt) => self.reconstruct_const(stmt),
Statement::Definition(stmt) => self.reconstruct_definition(stmt),
Statement::Expression(stmt) => self.reconstruct_expression_statement(stmt),
Statement::Iteration(stmt) => self.reconstruct_iteration(*stmt),
Expand Down Expand Up @@ -287,6 +288,19 @@ pub trait StatementReconstructor: ExpressionReconstructor {
)
}

fn reconstruct_const(&mut self, input: ConstDeclaration) -> (Statement, Self::AdditionalOutput) {
(
Statement::Const(ConstDeclaration {
place: input.place,
type_: input.type_,
value: self.reconstruct_expression(input.value).0,
span: input.span,
id: input.id,
}),
Default::default(),
)
}

fn reconstruct_definition(&mut self, input: DefinitionStatement) -> (Statement, Self::AdditionalOutput) {
(
Statement::Definition(DefinitionStatement {
Expand Down Expand Up @@ -368,6 +382,14 @@ pub trait ProgramReconstructor: StatementReconstructor {
structs: input.structs.into_iter().map(|(i, c)| (i, self.reconstruct_struct(c))).collect(),
mappings: input.mappings.into_iter().map(|(id, mapping)| (id, self.reconstruct_mapping(mapping))).collect(),
functions: input.functions.into_iter().map(|(i, f)| (i, self.reconstruct_function(f))).collect(),
consts: input
.consts
.into_iter()
.map(|(i, c)| match self.reconstruct_const(c) {
(Statement::Const(declaration), _) => (i, declaration),
_ => unreachable!("`reconstruct_const` can only return `Statement::Const`"),
})
.collect(),
span: input.span,
}
}
Expand Down
13 changes: 10 additions & 3 deletions compiler/ast/src/passes/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ pub trait StatementVisitor<'a>: ExpressionVisitor<'a> {
Statement::Block(stmt) => self.visit_block(stmt),
Statement::Conditional(stmt) => self.visit_conditional(stmt),
Statement::Console(stmt) => self.visit_console(stmt),
Statement::Const(stmt) => self.visit_const(stmt),
Statement::Definition(stmt) => self.visit_definition(stmt),
Statement::Expression(stmt) => self.visit_expression_statement(stmt),
Statement::Iteration(stmt) => self.visit_iteration(stmt),
Expand Down Expand Up @@ -177,6 +178,10 @@ pub trait StatementVisitor<'a>: ExpressionVisitor<'a> {
};
}

fn visit_const(&mut self, input: &'a ConstDeclaration) {
self.visit_expression(&input.value, &Default::default());
}

fn visit_definition(&mut self, input: &'a DefinitionStatement) {
self.visit_expression(&input.value, &Default::default());
}
Expand Down Expand Up @@ -210,11 +215,13 @@ pub trait ProgramVisitor<'a>: StatementVisitor<'a> {
}

fn visit_program_scope(&mut self, input: &'a ProgramScope) {
input.structs.values().for_each(|function| self.visit_struct(function));
input.structs.iter().for_each(|(_, c)| (self.visit_struct(c)));

input.mappings.iter().for_each(|(_, c)| (self.visit_mapping(c)));

input.mappings.values().for_each(|mapping| self.visit_mapping(mapping));
input.functions.iter().for_each(|(_, c)| (self.visit_function(c)));

input.functions.values().for_each(|function| self.visit_function(function));
input.consts.iter().for_each(|(_, c)| (self.visit_const(c)));
}

fn visit_import(&mut self, input: &'a Program) {
Expand Down
17 changes: 9 additions & 8 deletions compiler/ast/src/program/program_scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@

//! A Leo program scope consists of struct, function, and mapping definitions.

use crate::{Function, Mapping, ProgramId, Struct};
use crate::{ConstDeclaration, Function, Mapping, ProgramId, Struct};

use indexmap::IndexMap;
use leo_span::{Span, Symbol};
use serde::{Deserialize, Serialize};
use std::fmt;
Expand All @@ -28,12 +27,14 @@ use std::fmt;
pub struct ProgramScope {
/// The program id of the program scope.
pub program_id: ProgramId,
/// A map from struct names to struct definitions.
pub structs: IndexMap<Symbol, Struct>,
/// A map from mapping names to mapping definitions.
pub mappings: IndexMap<Symbol, Mapping>,
/// A map from function names to function definitions.
pub functions: IndexMap<Symbol, Function>,
/// 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 definitions.
pub functions: Vec<(Symbol, Function)>,
/// The span associated with the program scope.
pub span: Span,
}
Expand Down
46 changes: 46 additions & 0 deletions compiler/ast/src/statement/const_.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// 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::{Expression, Identifier, Node, NodeID, Type};
use leo_span::Span;

use serde::{Deserialize, Serialize};
use std::fmt;

/// A constant declaration statement.
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
pub struct ConstDeclaration {
/// The place to assign to. As opposed to `DefinitionStatement`, this can only be an identifier
pub place: Identifier,
/// The type of the binding, if specified, or inferred otherwise.
pub type_: Type,
/// An initializer value for the binding.
pub value: Expression,
/// The span excluding the semicolon.
pub span: Span,
/// The ID of the node.
pub id: NodeID,
}

impl fmt::Display for ConstDeclaration {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.place)?;
write!(f, ": {}", self.type_)?;
write!(f, " = {};", self.value)
}
}

crate::simple_node_impl!(ConstDeclaration);
10 changes: 10 additions & 0 deletions compiler/ast/src/statement/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ pub use conditional::*;
pub mod console;
pub use console::*;

pub mod const_;
pub use const_::*;

pub mod definition;
pub use definition::*;

Expand Down Expand Up @@ -61,6 +64,8 @@ pub enum Statement {
Conditional(ConditionalStatement),
/// A console logging statement.
Console(ConsoleStatement),
/// A binding from identifier to constant value.
Const(ConstDeclaration),
/// A binding or set of bindings / variables to declare.
Definition(DefinitionStatement),
/// An expression statement
Expand All @@ -86,6 +91,7 @@ impl fmt::Display for Statement {
Statement::Block(x) => x.fmt(f),
Statement::Conditional(x) => x.fmt(f),
Statement::Console(x) => x.fmt(f),
Statement::Const(x) => x.fmt(f),
Statement::Definition(x) => x.fmt(f),
Statement::Expression(x) => x.fmt(f),
Statement::Iteration(x) => x.fmt(f),
Expand All @@ -103,6 +109,7 @@ impl Node for Statement {
Block(n) => n.span(),
Conditional(n) => n.span(),
Console(n) => n.span(),
Const(n) => n.span(),
Definition(n) => n.span(),
Expression(n) => n.span(),
Iteration(n) => n.span(),
Expand All @@ -118,6 +125,7 @@ impl Node for Statement {
Block(n) => n.set_span(span),
Conditional(n) => n.set_span(span),
Console(n) => n.set_span(span),
Const(n) => n.set_span(span),
Definition(n) => n.set_span(span),
Expression(n) => n.set_span(span),
Iteration(n) => n.set_span(span),
Expand All @@ -133,6 +141,7 @@ impl Node for Statement {
Block(n) => n.id(),
Conditional(n) => n.id(),
Console(n) => n.id(),
Const(n) => n.id(),
Definition(n) => n.id(),
Expression(n) => n.id(),
Iteration(n) => n.id(),
Expand All @@ -148,6 +157,7 @@ impl Node for Statement {
Block(n) => n.set_id(id),
Conditional(n) => n.set_id(id),
Console(n) => n.set_id(id),
Const(n) => n.set_id(id),
Definition(n) => n.set_id(id),
Expression(n) => n.set_id(id),
Iteration(n) => n.set_id(id),
Expand Down
19 changes: 12 additions & 7 deletions compiler/parser/src/parser/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,23 +138,28 @@ impl ParserContext<'_> {
self.expect(&Token::LeftCurly)?;

// Parse the body of the program scope.
let mut functions = IndexMap::new();
let mut structs = IndexMap::new();
let mut mappings = IndexMap::new();
let mut consts: Vec<(Symbol, ConstDeclaration)> = Vec::new();
let mut functions: Vec<(Symbol, Function)> = Vec::new();
let mut structs: Vec<(Symbol, Struct)> = Vec::new();
let mut mappings: Vec<(Symbol, Mapping)> = Vec::new();

while self.has_next() {
match &self.token.token {
Token::Const => {
let declaration = self.parse_const_declaration_statement()?;
consts.push((Symbol::intern(&declaration.place.to_string()), declaration));
}
Token::Struct | Token::Record => {
let (id, struct_) = self.parse_struct()?;
structs.insert(id, struct_);
structs.push((id, struct_));
}
Token::Mapping => {
let (id, mapping) = self.parse_mapping()?;
mappings.insert(id, mapping);
mappings.push((id, mapping));
}
Token::At | Token::Function | Token::Transition | Token::Inline => {
let (id, function) = self.parse_function()?;
functions.insert(id, function);
functions.push((id, function));
}
Token::RightCurly => break,
_ => {
Expand All @@ -175,7 +180,7 @@ impl ParserContext<'_> {
// Parse `}`.
let end = self.expect(&Token::RightCurly)?;

Ok(ProgramScope { program_id, functions, structs, mappings, span: start + end })
Ok(ProgramScope { program_id, consts, functions, structs, mappings, span: start + end })
}

/// Returns a [`Vec<Member>`] AST node if the next tokens represent a struct member.
Expand Down
16 changes: 16 additions & 0 deletions compiler/parser/src/parser/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ impl ParserContext<'_> {
Token::For => Ok(Statement::Iteration(Box::new(self.parse_loop_statement()?))),
Token::Assert | Token::AssertEq | Token::AssertNeq => Ok(self.parse_assert_statement()?),
Token::Let => Ok(Statement::Definition(self.parse_definition_statement()?)),
Token::Const => Ok(Statement::Const(self.parse_const_declaration_statement()?)),
Token::LeftCurly => Ok(Statement::Block(self.parse_block()?)),
Token::Console => Err(ParserError::console_statements_are_not_yet_supported(self.token.span).into()),
Token::Finalize => Err(ParserError::finalize_statements_are_deprecated(self.token.span).into()),
Expand Down Expand Up @@ -314,6 +315,21 @@ impl ParserContext<'_> {
Ok(ConsoleStatement { span: keyword + span, function, id: self.node_builder.next_id() })
}

/// Returns a [`ConstDeclaration`] AST node if the next tokens represent a const declaration statement.
pub(super) fn parse_const_declaration_statement(&mut self) -> Result<ConstDeclaration> {
self.expect(&Token::Const)?;
let decl_span = self.prev_token.span;

// Parse variable name and type.
let (place, type_, _) = self.parse_typed_ident()?;

self.expect(&Token::Assign)?;
let value = self.parse_expression()?;
self.expect(&Token::Semicolon)?;

Ok(ConstDeclaration { span: decl_span + value.span(), place, type_, value, id: self.node_builder.next_id() })
}

/// Returns a [`DefinitionStatement`] AST node if the next tokens represent a definition statement.
pub(super) fn parse_definition_statement(&mut self) -> Result<DefinitionStatement> {
self.expect(&Token::Let)?;
Expand Down
1 change: 1 addition & 0 deletions compiler/parser/src/tokenizer/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,7 @@ impl Token {
"block" => Token::Block,
"bool" => Token::Bool,
"console" => Token::Console,
"const" => Token::Const,
"constant" => Token::Constant,
"else" => Token::Else,
"false" => Token::False,
Expand Down
4 changes: 4 additions & 0 deletions compiler/parser/src/tokenizer/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ pub enum Token {
AssertEq,
AssertNeq,
Console,
Const,
Constant,
Else,
Finalize,
Expand Down Expand Up @@ -154,6 +155,7 @@ pub const KEYWORD_TOKENS: &[Token] = &[
Token::AssertNeq,
Token::Bool,
Token::Console,
Token::Const,
Token::Constant,
Token::Else,
Token::False,
Expand Down Expand Up @@ -210,6 +212,7 @@ impl Token {
Token::Block => sym::block,
Token::Bool => sym::bool,
Token::Console => sym::console,
Token::Const => sym::Const,
Token::Constant => sym::constant,
Token::Else => sym::Else,
Token::False => sym::False,
Expand Down Expand Up @@ -343,6 +346,7 @@ impl fmt::Display for Token {
AssertEq => write!(f, "assert_eq"),
AssertNeq => write!(f, "assert_neq"),
Console => write!(f, "console"),
Const => write!(f, "const"),
Constant => write!(f, "constant"),
Else => write!(f, "else"),
Finalize => write!(f, "finalize"),
Expand Down
5 changes: 3 additions & 2 deletions compiler/passes/src/code_generation/visit_expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -494,8 +494,9 @@ impl<'a> CodeGenerator<'a> {
Expression::Identifier(identifier) => identifier.name,
_ => unreachable!("Parsing guarantees that a function name is always an identifier."),
};
let has_finalize = match imported_program_scope.functions.get(&function_name) {
Some(function) => function.finalize.is_some(),
let has_finalize = match imported_program_scope.functions.iter().find(|(sym, _)| *sym == function_name)
{
Some((_, function)) => function.finalize.is_some(),
None => unreachable!("Type checking guarantees that imported functions are well defined."),
};
(format!(" call {external}.aleo/{}", input.function), has_finalize)
Expand Down
13 changes: 9 additions & 4 deletions compiler/passes/src/code_generation/visit_program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,16 @@ 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.get(&name) {
match structs_map.get(&name) {
// If the struct is found, it is a local struct.
Some(struct_) => self.visit_struct_or_record(struct_),
// If the struct is not found, it is an imported struct.
Expand All @@ -78,16 +82,17 @@ impl<'a> CodeGenerator<'a> {
program_string.push('\n');

// Visit each mapping in the Leo AST and produce an Aleo mapping declaration.
program_string.push_str(&program_scope.mappings.values().map(|mapping| self.visit_mapping(mapping)).join("\n"));
program_string
.push_str(&program_scope.mappings.iter().map(|(_, mapping)| self.visit_mapping(mapping)).join("\n"));

// Visit each function in the program scope and produce an Aleo function.
// Note that in the function inlining pass, we reorder the functions such that they are in post-order.
// In other words, a callee function precedes its caller function in the program scope.
program_string.push_str(
&program_scope
.functions
.values()
.map(|function| {
.iter()
.map(|(_, function)| {
// Set the `is_transition_function` flag.
self.is_transition_function = matches!(function.variant, Variant::Transition);

Expand Down
Loading

0 comments on commit bd9714a

Please sign in to comment.