From 40ff47882f3140258bbc67c8a60b33a19b592c45 Mon Sep 17 00:00:00 2001 From: d0cd Date: Fri, 21 Oct 2022 18:31:48 -0700 Subject: [PATCH] Add support for expression statements in compiler passes --- .../src/code_generation/visit_expressions.rs | 1 + .../src/code_generation/visit_statements.rs | 12 ++++++++++-- .../rename_statement.rs | 18 ++++++++++++++++-- .../src/type_checking/check_statements.rs | 14 ++++++++++++++ .../errors/type_checker/type_checker_error.rs | 7 +++++++ 5 files changed, 48 insertions(+), 4 deletions(-) diff --git a/compiler/passes/src/code_generation/visit_expressions.rs b/compiler/passes/src/code_generation/visit_expressions.rs index 05f4fd5588..f8dd11580d 100644 --- a/compiler/passes/src/code_generation/visit_expressions.rs +++ b/compiler/passes/src/code_generation/visit_expressions.rs @@ -276,6 +276,7 @@ impl<'a> CodeGenerator<'a> { } } + // TODO: Fix to allow zero or multiple outputs. fn visit_call(&mut self, input: &'a CallExpression) -> (String, String) { let mut call_instruction = match &input.external { Some(external) => format!(" call {external}.aleo/{} ", input.function), diff --git a/compiler/passes/src/code_generation/visit_statements.rs b/compiler/passes/src/code_generation/visit_statements.rs index 211159d07e..66515b4e77 100644 --- a/compiler/passes/src/code_generation/visit_statements.rs +++ b/compiler/passes/src/code_generation/visit_statements.rs @@ -18,8 +18,8 @@ use crate::CodeGenerator; use leo_ast::{ AssignStatement, Block, ConditionalStatement, ConsoleFunction, ConsoleStatement, DecrementStatement, - DefinitionStatement, Expression, FinalizeStatement, IncrementStatement, IterationStatement, Mode, Output, - ReturnStatement, Statement, + DefinitionStatement, Expression, ExpressionStatement, FinalizeStatement, IncrementStatement, IterationStatement, + Mode, Output, ReturnStatement, Statement, }; use itertools::Itertools; @@ -34,6 +34,7 @@ impl<'a> CodeGenerator<'a> { Statement::Console(stmt) => self.visit_console(stmt), Statement::Decrement(stmt) => self.visit_decrement(stmt), Statement::Definition(stmt) => self.visit_definition(stmt), + Statement::Expression(stmt) => self.visit_expression_statement(stmt), Statement::Finalize(stmt) => self.visit_finalize(stmt), Statement::Increment(stmt) => self.visit_increment(stmt), Statement::Iteration(stmt) => self.visit_iteration(stmt), @@ -110,6 +111,13 @@ impl<'a> CodeGenerator<'a> { unreachable!("DefinitionStatement's should not exist in SSA form.") } + fn visit_expression_statement(&mut self, input: &'a ExpressionStatement) -> String { + match input.expression { + Expression::Call(_) => self.visit_expression(&input.expression).1, + _ => unreachable!("ExpressionStatement's can only contain CallExpression's."), + } + } + fn visit_increment(&mut self, input: &'a IncrementStatement) -> String { let (index, mut instructions) = self.visit_expression(&input.index); let (amount, amount_instructions) = self.visit_expression(&input.amount); diff --git a/compiler/passes/src/static_single_assignment/rename_statement.rs b/compiler/passes/src/static_single_assignment/rename_statement.rs index 8fefc93cdc..9890ea5e31 100644 --- a/compiler/passes/src/static_single_assignment/rename_statement.rs +++ b/compiler/passes/src/static_single_assignment/rename_statement.rs @@ -18,8 +18,8 @@ use crate::{RenameTable, StaticSingleAssigner}; use leo_ast::{ AssignStatement, Block, ConditionalStatement, ConsoleFunction, ConsoleStatement, DecrementStatement, - DefinitionStatement, Expression, ExpressionConsumer, FinalizeStatement, Identifier, IncrementStatement, - IterationStatement, ReturnStatement, Statement, StatementConsumer, TernaryExpression, + DefinitionStatement, Expression, ExpressionConsumer, ExpressionStatement, FinalizeStatement, Identifier, + IncrementStatement, IterationStatement, ReturnStatement, Statement, StatementConsumer, TernaryExpression, }; use leo_span::Symbol; @@ -234,6 +234,20 @@ impl StatementConsumer for StaticSingleAssigner<'_> { statements } + /// Consumes the expressions associated with `ExpressionStatement`, returning the simplified `ExpressionStatement`. + fn consume_expression_statement(&mut self, input: ExpressionStatement) -> Self::Output { + // Process the expression associated with the `ExpressionStatement`. + let (expression, mut statements) = self.consume_expression(input.expression); + + // Add the `ExpressionStatement` to the list of produced statements. + statements.push(Statement::Expression(ExpressionStatement { + expression, + span: input.span, + })); + + statements + } + /// Consumes the expressions associated with the `FinalizeStatement`, returning the simplified `FinalizeStatement`. fn consume_finalize(&mut self, input: FinalizeStatement) -> Self::Output { let mut statements = Vec::new(); diff --git a/compiler/passes/src/type_checking/check_statements.rs b/compiler/passes/src/type_checking/check_statements.rs index 1074fd40b6..56bb5b80ed 100644 --- a/compiler/passes/src/type_checking/check_statements.rs +++ b/compiler/passes/src/type_checking/check_statements.rs @@ -34,6 +34,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> { Statement::Console(stmt) => self.visit_console(stmt), Statement::Decrement(stmt) => self.visit_decrement(stmt), Statement::Definition(stmt) => self.visit_definition(stmt), + Statement::Expression(stmt) => self.visit_expression_statement(stmt), Statement::Finalize(stmt) => self.visit_finalize(stmt), Statement::Increment(stmt) => self.visit_increment(stmt), Statement::Iteration(stmt) => self.visit_iteration(stmt), @@ -224,6 +225,19 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> { } } + fn visit_expression_statement(&mut self, input: &'a ExpressionStatement) { + // Expression statements can only be function calls. + if !matches!(input.expression, Expression::Call(_)) { + self.emit_err(TypeCheckerError::expression_statement_must_be_function_call( + input.span(), + )); + } else { + // Check the expression. + // TODO: Should the output type be restricted to unit types? + self.visit_expression(&input.expression, &None); + } + } + fn visit_finalize(&mut self, input: &'a FinalizeStatement) { if self.is_finalize { self.emit_err(TypeCheckerError::finalize_in_finalize(input.span())); diff --git a/errors/src/errors/type_checker/type_checker_error.rs b/errors/src/errors/type_checker/type_checker_error.rs index 9d306669ac..c270b5101a 100644 --- a/errors/src/errors/type_checker/type_checker_error.rs +++ b/errors/src/errors/type_checker/type_checker_error.rs @@ -512,4 +512,11 @@ create_messages!( msg: format!("A finalize statement cannot contain tuple expressions."), help: None, } + + @formatted + expression_statement_must_be_function_call { + args: (), + msg: format!("An expression statement must be a function call."), + help: None, + } );