Parser support for transition keyword

This commit is contained in:
Pranav Gaddamadugu 2022-10-03 08:53:44 -07:00
parent 62b16cfa51
commit 80d8880292
8 changed files with 55 additions and 19 deletions

View File

@ -0,0 +1,28 @@
// Copyright (C) 2019-2022 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 serde::{Deserialize, Serialize};
/// An enum declaring how the function is invoked.
/// A transition function is permitted the ability to manipulate records.
/// A regular function is not permitted to manipulate records.
/// An inline function is directly copied at the call site.
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub enum CallType {
Inline,
Standard,
Transition,
}

View File

@ -17,6 +17,9 @@
pub mod annotation;
pub use annotation::*;
pub mod call_type;
pub use call_type::*;
pub mod external;
pub use external::*;
@ -43,6 +46,8 @@ use std::fmt;
pub struct Function {
/// Annotations on the function.
pub annotations: Vec<Annotation>,
/// Is this function a transition, inlined, or a regular function?.
pub call_type: CallType,
/// The function identifier, e.g., `foo` in `function foo(...) { ... }`.
pub identifier: Identifier,
/// The function's input parameters.
@ -69,8 +74,10 @@ impl Eq for Function {}
impl Function {
/// Initialize a new function.
#[allow(clippy::too_many_arguments)]
pub fn new(
annotations: Vec<Annotation>,
call_type: CallType,
identifier: Identifier,
input: Vec<Input>,
output: Vec<Output>,
@ -92,6 +99,7 @@ impl Function {
Function {
annotations,
call_type,
identifier,
input,
output,
@ -115,7 +123,12 @@ impl Function {
/// Private formatting method used for optimizing [fmt::Debug] and [fmt::Display] implementations.
///
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "function {}", self.identifier)?;
match self.call_type {
CallType::Inline => write!(f, "inline ")?,
CallType::Standard => write!(f, "function ")?,
CallType::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() {

View File

@ -341,6 +341,7 @@ pub trait ProgramReconstructor: StatementReconstructor {
fn reconstruct_function(&mut self, input: Function) -> Function {
Function {
annotations: input.annotations,
call_type: input.call_type,
identifier: input.identifier,
input: input.input,
output: input.output,

View File

@ -177,7 +177,7 @@ impl<'a> ParserContext<'a> {
}
/// Returns an unexpected error at the current token.
fn unexpected<T>(&self, expected: impl Display) -> Result<T> {
pub(super) fn unexpected<T>(&self, expected: impl Display) -> Result<T> {
Err(ParserError::unexpected(&self.token.token, expected, self.token.span).into())
}

View File

@ -51,12 +51,8 @@ impl ParserContext<'_> {
let (id, function) = self.parse_function()?;
functions.insert(id, function);
}
Token::Const if self.peek_is_function() => {
let (id, function) = self.parse_function()?;
functions.insert(id, function);
}
Token::Identifier(sym::test) => return Err(ParserError::test_function(self.token.span).into()),
Token::Function => {
Token::Function | Token::Transition => {
let (id, function) = self.parse_function()?;
functions.insert(id, function);
}
@ -330,15 +326,6 @@ impl ParserContext<'_> {
)
}
/// Returns `true` if the next token is Function or if it is a Const followed by Function.
/// Returns `false` otherwise.
fn peek_is_function(&self) -> bool {
matches!(
(&self.token.token, self.look_ahead(1, |t| &t.token)),
(Token::Function, _) | (Token::Const, Token::Function)
)
}
/// Returns an [`Annotation`] AST node if the next tokens represent an annotation.
fn parse_annotation(&mut self) -> Result<Annotation> {
// Parse the `@` symbol and identifier.
@ -364,8 +351,12 @@ impl ParserContext<'_> {
while self.look_ahead(0, |t| &t.token) == &Token::At {
annotations.push(self.parse_annotation()?)
}
// Parse `function IDENT`.
let start = self.expect(&Token::Function)?;
// Parse `<call_type> IDENT`, where `<call_type>` is `function` or `transition`.
let (call_type, start) = match self.token.token {
Token::Function => (CallType::Standard, self.expect(&Token::Function)?),
Token::Transition => (CallType::Transition, self.expect(&Token::Transition)?),
_ => self.unexpected("'function', 'transition'")?,
};
let name = self.expect_identifier()?;
// Parse parameters.
@ -426,7 +417,7 @@ impl ParserContext<'_> {
let span = start + block.span;
Ok((
name,
Function::new(annotations, name, inputs, output, block, finalize, span),
Function::new(annotations, call_type, name, inputs, output, block, finalize, span),
))
}
}

View File

@ -131,6 +131,7 @@ impl ProgramReconstructor for Flattener<'_> {
Function {
annotations: function.annotations,
call_type: function.call_type,
identifier: function.identifier,
input: function.input,
output: function.output,

View File

@ -58,6 +58,7 @@ impl ProgramReconstructor for Unroller<'_> {
// Reconstruct the function block.
let reconstructed_function = Function {
annotations: function.annotations,
call_type: function.call_type,
identifier: function.identifier,
input: function.input,
output: function.output,

View File

@ -72,6 +72,7 @@ impl FunctionConsumer for StaticSingleAssigner {
Function {
annotations: function.annotations,
call_type: function.call_type,
identifier: function.identifier,
input: function.input,
output: function.output,