Merge pull request #1908 from AleoHQ/refactor/visitor

Refactor Visitor and Reconstructor pattern.
This commit is contained in:
Collin Chin 2022-07-02 13:20:45 -07:00 committed by GitHub
commit 2bc5f66cc1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 848 additions and 1701 deletions

View File

@ -19,14 +19,8 @@
// todo @gluax: Move the files in this module into `leo-passes` in a future PR.
// pub mod reconstructing_reducer;
// pub use reconstructing_reducer::*;
//
// pub mod reconstructing_director;
// pub use reconstructing_director::*;
pub mod reconstructor;
pub use reconstructor::*;
pub mod visitor;
pub use visitor::*;
pub mod visitor_director;
pub use visitor_director::*;

View File

@ -1,340 +0,0 @@
// 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/>.
//! This module contains a Director for how to map over the AST
//! and applies a reducer call to each node.
use crate::*;
use leo_errors::{AstError, Result};
use leo_span::Span;
use indexmap::IndexMap;
pub struct ReconstructingDirector<R: ReconstructingReducer> {
reducer: R,
}
impl<R: ReconstructingReducer> ReconstructingDirector<R> {
pub fn new(reducer: R) -> Self {
Self { reducer }
}
pub fn reduce_type(&mut self, type_: &Type, span: &Span) -> Result<Type> {
self.reducer.reduce_type(type_, *type_, span)
}
// Expressions
pub fn reduce_expression(&mut self, expression: &Expression) -> Result<Expression> {
let new = match expression {
Expression::Identifier(identifier) => Expression::Identifier(self.reduce_identifier(identifier)?),
Expression::Literal(lit) => self.reduce_literal(lit)?,
Expression::Binary(binary) => Expression::Binary(self.reduce_binary(binary)?),
Expression::Unary(unary) => Expression::Unary(self.reduce_unary(unary)?),
Expression::Ternary(ternary) => Expression::Ternary(self.reduce_ternary(ternary)?),
Expression::Call(call) => Expression::Call(self.reduce_call(call)?),
Expression::CircuitInit(circuit_init) => Expression::CircuitInit(self.reduce_circuit_init(circuit_init)?),
Expression::Err(s) => Expression::Err(s.clone()),
};
self.reducer.reduce_expression(expression, new)
}
pub fn reduce_identifier(&mut self, identifier: &Identifier) -> Result<Identifier> {
self.reducer.reduce_identifier(identifier)
}
pub fn reduce_group_tuple(&mut self, group_tuple: &GroupTuple) -> Result<GroupTuple> {
self.reducer.reduce_group_tuple(group_tuple)
}
pub fn reduce_group_literal(&mut self, group_lit: &GroupLiteral) -> Result<GroupLiteral> {
let new = match group_lit {
GroupLiteral::Tuple(group_tuple) => GroupLiteral::Tuple(self.reduce_group_tuple(group_tuple)?),
_ => group_lit.clone(),
};
self.reducer.reduce_group_literal(group_lit, new)
}
pub fn reduce_string(&mut self, string: &str, span: &Span) -> Result<Expression> {
self.reducer.reduce_string(string, span)
}
pub fn reduce_literal(&mut self, lit: &LiteralExpression) -> Result<Expression> {
let new = match lit {
LiteralExpression::Group(group_value) => Expression::Literal(LiteralExpression::Group(Box::new(
self.reduce_group_literal(group_value)?,
))),
LiteralExpression::String(string, span) => self.reduce_string(string, span)?,
_ => Expression::Literal(lit.clone()),
};
self.reducer.reduce_literal(lit, new)
}
pub fn reduce_binary(&mut self, binary: &BinaryExpression) -> Result<BinaryExpression> {
let left = self.reduce_expression(&binary.left)?;
let right = self.reduce_expression(&binary.right)?;
self.reducer.reduce_binary(binary, left, right, binary.op)
}
pub fn reduce_unary(&mut self, unary: &UnaryExpression) -> Result<UnaryExpression> {
let inner = self.reduce_expression(&unary.receiver)?;
self.reducer.reduce_unary(unary, inner, unary.op)
}
pub fn reduce_ternary(&mut self, ternary: &TernaryExpression) -> Result<TernaryExpression> {
let condition = self.reduce_expression(&ternary.condition)?;
let if_true = self.reduce_expression(&ternary.if_true)?;
let if_false = self.reduce_expression(&ternary.if_false)?;
self.reducer.reduce_ternary(ternary, condition, if_true, if_false)
}
pub fn reduce_call(&mut self, call: &CallExpression) -> Result<CallExpression> {
let function = self.reduce_expression(&call.function)?;
let mut arguments = vec![];
for argument in call.arguments.iter() {
arguments.push(self.reduce_expression(argument)?);
}
self.reducer.reduce_call(call, function, arguments)
}
// Statements
pub fn reduce_statement(&mut self, statement: &Statement) -> Result<Statement> {
let new = match statement {
Statement::Return(return_statement) => Statement::Return(self.reduce_return(return_statement)?),
Statement::Definition(definition) => Statement::Definition(self.reduce_definition(definition)?),
Statement::Assign(assign) => Statement::Assign(Box::new(self.reduce_assign(assign)?)),
Statement::Conditional(conditional) => Statement::Conditional(self.reduce_conditional(conditional)?),
Statement::Iteration(iteration) => Statement::Iteration(Box::new(self.reduce_iteration(iteration)?)),
Statement::Console(console) => Statement::Console(self.reduce_console(console)?),
Statement::Block(block) => Statement::Block(self.reduce_block(block)?),
};
self.reducer.reduce_statement(statement, new)
}
pub fn reduce_return(&mut self, return_statement: &ReturnStatement) -> Result<ReturnStatement> {
let expression = self.reduce_expression(&return_statement.expression)?;
self.reducer.reduce_return(return_statement, expression)
}
pub fn reduce_variable_name(&mut self, variable_name: &VariableName) -> Result<VariableName> {
let identifier = self.reduce_identifier(&variable_name.identifier)?;
self.reducer.reduce_variable_name(variable_name, identifier)
}
pub fn reduce_definition(&mut self, definition: &DefinitionStatement) -> Result<DefinitionStatement> {
let mut variable_names = vec![];
for variable_name in definition.variable_names.iter() {
variable_names.push(self.reduce_variable_name(variable_name)?);
}
let type_ = self.reduce_type(&definition.type_, &definition.span)?;
let value = self.reduce_expression(&definition.value)?;
self.reducer.reduce_definition(definition, variable_names, type_, value)
}
pub fn reduce_assign(&mut self, assign: &AssignStatement) -> Result<AssignStatement> {
let place = self.reduce_expression(&assign.place)?;
let value = self.reduce_expression(&assign.value)?;
self.reducer.reduce_assign(assign, place, value)
}
pub fn reduce_conditional(&mut self, conditional: &ConditionalStatement) -> Result<ConditionalStatement> {
let condition = self.reduce_expression(&conditional.condition)?;
let block = self.reduce_block(&conditional.block)?;
let next = conditional
.next
.as_ref()
.map(|condition| self.reduce_statement(condition))
.transpose()?;
self.reducer.reduce_conditional(conditional, condition, block, next)
}
pub fn reduce_iteration(&mut self, iteration: &IterationStatement) -> Result<IterationStatement> {
let variable = self.reduce_identifier(&iteration.variable)?;
let type_ = self.reduce_type(&iteration.type_, &iteration.span())?;
let start = self.reduce_expression(&iteration.start)?;
let stop = self.reduce_expression(&iteration.stop)?;
let block = self.reduce_block(&iteration.block)?;
self.reducer
.reduce_iteration(iteration, variable, type_, start, stop, block)
}
pub fn reduce_console(&mut self, console_function_call: &ConsoleStatement) -> Result<ConsoleStatement> {
let function = match &console_function_call.function {
ConsoleFunction::Assert(expression) => ConsoleFunction::Assert(self.reduce_expression(expression)?),
ConsoleFunction::Error(args) | ConsoleFunction::Log(args) => {
let mut parameters = vec![];
for parameter in args.parameters.iter() {
parameters.push(self.reduce_expression(parameter)?);
}
let formatted = ConsoleArgs {
string: args.string.clone(),
parameters,
span: args.span,
};
match &console_function_call.function {
ConsoleFunction::Error(_) => ConsoleFunction::Error(formatted),
ConsoleFunction::Log(_) => ConsoleFunction::Log(formatted),
_ => return Err(AstError::impossible_console_assert_call(args.span).into()),
}
}
};
self.reducer.reduce_console(console_function_call, function)
}
pub fn reduce_block(&mut self, block: &Block) -> Result<Block> {
let mut statements = vec![];
for statement in block.statements.iter() {
statements.push(self.reduce_statement(statement)?);
}
self.reducer.reduce_block(block, statements)
}
// Program
pub fn reduce_program(&mut self, program: &Program) -> Result<Program> {
let mut inputs = vec![];
for input in program.expected_input.iter() {
inputs.push(self.reduce_function_input(input)?);
}
let mut functions = IndexMap::new();
let mut circuits = IndexMap::new();
for (name, function) in program.functions.iter() {
functions.insert(*name, self.reduce_function(function)?);
}
for (name, circuit) in program.circuits.iter() {
circuits.insert(*name, self.reduce_circuit(circuit)?);
}
self.reducer.reduce_program(program, inputs, functions, circuits)
}
// Functions
pub fn reduce_function_input_variable(
&mut self,
variable: &FunctionInputVariable,
) -> Result<FunctionInputVariable> {
let identifier = self.reduce_identifier(&variable.identifier)?;
let type_ = self.reduce_type(&variable.type_, &variable.span)?;
self.reducer.reduce_function_input_variable(variable, identifier, type_)
}
pub fn reduce_function_input(&mut self, input: &FunctionInput) -> Result<FunctionInput> {
let new = match input {
FunctionInput::Variable(function_input_variable) => {
FunctionInput::Variable(self.reduce_function_input_variable(function_input_variable)?)
}
};
self.reducer.reduce_function_input(input, new)
}
pub fn reduce_function(&mut self, function: &Function) -> Result<Function> {
let identifier = self.reduce_identifier(&function.identifier)?;
let mut inputs = vec![];
for input in function.input.iter() {
inputs.push(self.reduce_function_input(input)?);
}
let output = self.reduce_type(&function.output, &function.span)?;
let block = self.reduce_block(&function.block)?;
self.reducer
.reduce_function(function, identifier, inputs, output, block)
}
// Circuits
pub fn reduce_circuit_variable_initializer(
&mut self,
variable: &CircuitVariableInitializer,
) -> Result<CircuitVariableInitializer> {
let identifier = self.reduce_identifier(&variable.identifier)?;
let expression = variable
.expression
.as_ref()
.map(|expr| self.reduce_expression(expr))
.transpose()?;
self.reducer
.reduce_circuit_variable_initializer(variable, identifier, expression)
}
pub fn reduce_circuit_init(&mut self, circuit_init: &CircuitInitExpression) -> Result<CircuitInitExpression> {
let name = self.reduce_identifier(&circuit_init.name)?;
let mut members = vec![];
for member in circuit_init.members.iter() {
members.push(self.reduce_circuit_variable_initializer(member)?);
}
self.reducer.reduce_circuit_init(circuit_init, name, members)
}
pub fn reduce_circuit_member(&mut self, circuit_member: &CircuitMember) -> Result<CircuitMember> {
let new = match circuit_member {
CircuitMember::CircuitConst(identifier, type_, value) => CircuitMember::CircuitConst(
self.reduce_identifier(identifier)?,
self.reduce_type(type_, &identifier.span)?,
self.reduce_expression(value)?,
),
CircuitMember::CircuitVariable(identifier, type_) => CircuitMember::CircuitVariable(
self.reduce_identifier(identifier)?,
self.reduce_type(type_, &identifier.span)?,
),
CircuitMember::CircuitFunction(function) => {
CircuitMember::CircuitFunction(Box::new(self.reduce_function(function)?))
}
};
self.reducer.reduce_circuit_member(circuit_member, new)
}
pub fn reduce_circuit(&mut self, circuit: &Circuit) -> Result<Circuit> {
let circuit_name = self.reduce_identifier(&circuit.identifier)?;
let mut members = vec![];
for member in circuit.members.iter() {
members.push(self.reduce_circuit_member(member)?);
}
self.reducer.reduce_circuit(circuit, circuit_name, members)
}
}

View File

@ -1,320 +0,0 @@
// 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/>.
//! This module contains a Reducer Trait for the AST.
//! It implements default methods for each node to be made
//! given the information of the old node.
use crate::*;
use leo_errors::Result;
use leo_span::{Span, Symbol};
use indexmap::IndexMap;
// Needed to fix clippy bug.
#[allow(clippy::redundant_closure)]
pub trait ReconstructingReducer {
fn in_circuit(&self) -> bool;
fn swap_in_circuit(&mut self);
fn reduce_type(&mut self, _type_: &Type, new: Type, _span: &Span) -> Result<Type> {
Ok(new)
}
// Expressions
fn reduce_expression(&mut self, _expression: &Expression, new: Expression) -> Result<Expression> {
Ok(new)
}
fn reduce_identifier(&mut self, identifier: &Identifier) -> Result<Identifier> {
Ok(Identifier {
name: identifier.name,
span: identifier.span,
})
}
fn reduce_group_tuple(&mut self, group_tuple: &GroupTuple) -> Result<GroupTuple> {
Ok(GroupTuple {
x: group_tuple.x.clone(),
y: group_tuple.y.clone(),
span: group_tuple.span,
})
}
fn reduce_group_literal(&mut self, _group_lit: &GroupLiteral, new: GroupLiteral) -> Result<GroupLiteral> {
Ok(new)
}
fn reduce_string(&mut self, string: &str, span: &Span) -> Result<Expression> {
Ok(Expression::Literal(LiteralExpression::String(
string.to_string(),
*span,
)))
}
fn reduce_literal(&mut self, _lit: &LiteralExpression, new: Expression) -> Result<Expression> {
Ok(new)
}
fn reduce_binary(
&mut self,
binary: &BinaryExpression,
left: Expression,
right: Expression,
op: BinaryOperation,
) -> Result<BinaryExpression> {
Ok(BinaryExpression {
left: Box::new(left),
right: Box::new(right),
op,
span: binary.span,
})
}
fn reduce_unary(
&mut self,
unary: &UnaryExpression,
inner: Expression,
op: UnaryOperation,
) -> Result<UnaryExpression> {
Ok(UnaryExpression {
receiver: Box::new(inner),
op,
span: unary.span,
})
}
fn reduce_ternary(
&mut self,
ternary: &TernaryExpression,
condition: Expression,
if_true: Expression,
if_false: Expression,
) -> Result<TernaryExpression> {
Ok(TernaryExpression {
condition: Box::new(condition),
if_true: Box::new(if_true),
if_false: Box::new(if_false),
span: ternary.span,
})
}
fn reduce_call(
&mut self,
call: &CallExpression,
function: Expression,
arguments: Vec<Expression>,
) -> Result<CallExpression> {
Ok(CallExpression {
function: Box::new(function),
arguments,
span: call.span,
})
}
// Statements
fn reduce_statement(&mut self, _statement: &Statement, new: Statement) -> Result<Statement> {
Ok(new)
}
fn reduce_return(&mut self, return_statement: &ReturnStatement, expression: Expression) -> Result<ReturnStatement> {
Ok(ReturnStatement {
expression,
span: return_statement.span,
})
}
fn reduce_variable_name(&mut self, variable_name: &VariableName, identifier: Identifier) -> Result<VariableName> {
Ok(VariableName {
mutable: variable_name.mutable,
identifier,
span: variable_name.span,
})
}
fn reduce_definition(
&mut self,
definition: &DefinitionStatement,
variable_names: Vec<VariableName>,
type_: Type,
value: Expression,
) -> Result<DefinitionStatement> {
Ok(DefinitionStatement {
declaration_type: definition.declaration_type,
variable_names,
type_,
value,
span: definition.span,
})
}
fn reduce_assign(
&mut self,
assign: &AssignStatement,
place: Expression,
value: Expression,
) -> Result<AssignStatement> {
Ok(AssignStatement {
operation: assign.operation,
place,
value,
span: assign.span,
})
}
fn reduce_conditional(
&mut self,
conditional: &ConditionalStatement,
condition: Expression,
block: Block,
statement: Option<Statement>,
) -> Result<ConditionalStatement> {
Ok(ConditionalStatement {
condition,
block,
next: statement.map(|statement| Box::new(statement)),
span: conditional.span,
})
}
fn reduce_iteration(
&mut self,
iteration: &IterationStatement,
variable: Identifier,
type_: Type,
start: Expression,
stop: Expression,
block: Block,
) -> Result<IterationStatement> {
Ok(IterationStatement {
variable,
type_,
start,
stop,
inclusive: iteration.inclusive,
block,
span: iteration.span,
})
}
fn reduce_console(&mut self, console: &ConsoleStatement, function: ConsoleFunction) -> Result<ConsoleStatement> {
Ok(ConsoleStatement {
function,
span: console.span,
})
}
fn reduce_block(&mut self, block: &Block, statements: Vec<Statement>) -> Result<Block> {
Ok(Block {
statements,
span: block.span,
})
}
#[allow(clippy::too_many_arguments)]
// Program
fn reduce_program(
&mut self,
program: &Program,
expected_input: Vec<FunctionInput>,
functions: IndexMap<Identifier, Function>,
circuits: IndexMap<Identifier, Circuit>,
) -> Result<Program> {
Ok(Program {
name: program.name.clone(),
expected_input,
functions,
circuits,
})
}
fn reduce_function_input_variable(
&mut self,
variable: &FunctionInputVariable,
identifier: Identifier,
type_: Type,
) -> Result<FunctionInputVariable> {
Ok(FunctionInputVariable::new(
identifier,
variable.mode(),
type_,
variable.span,
))
}
fn reduce_function_input(&mut self, _input: &FunctionInput, new: FunctionInput) -> Result<FunctionInput> {
Ok(new)
}
fn reduce_import(&mut self, identifier: Vec<Symbol>, import: Program) -> Result<(Vec<Symbol>, Program)> {
Ok((identifier, import))
}
#[allow(clippy::too_many_arguments)]
fn reduce_function(
&mut self,
function: &Function,
identifier: Identifier,
input: Vec<FunctionInput>,
output: Type,
block: Block,
) -> Result<Function> {
Ok(Function {
identifier,
input,
output,
block,
core_mapping: function.core_mapping.clone(),
span: function.span,
})
}
fn reduce_circuit_variable_initializer(
&mut self,
_variable: &CircuitVariableInitializer,
identifier: Identifier,
expression: Option<Expression>,
) -> Result<CircuitVariableInitializer> {
Ok(CircuitVariableInitializer { identifier, expression })
}
fn reduce_circuit_init(
&mut self,
circuit_init: &CircuitInitExpression,
name: Identifier,
members: Vec<CircuitVariableInitializer>,
) -> Result<CircuitInitExpression> {
Ok(CircuitInitExpression {
name,
members,
span: circuit_init.span.clone(),
})
}
fn reduce_circuit_member(&mut self, _circuit_member: &CircuitMember, new: CircuitMember) -> Result<CircuitMember> {
Ok(new)
}
fn reduce_circuit(
&mut self,
circuit: &Circuit,
circuit_name: Identifier,
members: Vec<CircuitMember>,
) -> Result<Circuit> {
Ok(Circuit { identifier: circuit_name, members, span: circuit.span.clone() })
}
}

View File

@ -0,0 +1,245 @@
// 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/>.
//! This module contains a Reconstructor trait for the AST.
//! It implements default methods for each node to be made
//! given the information of the old node.
use crate::*;
/// A Reconstructor trait for expressions in the AST.
pub trait ExpressionReconstructor {
type AdditionalOutput: Default;
fn reconstruct_expression(&mut self, input: Expression) -> (Expression, Self::AdditionalOutput) {
match input {
Expression::Access(access) => self.reconstruct_access(access),
Expression::Identifier(identifier) => self.reconstruct_identifier(identifier),
Expression::Literal(value) => self.reconstruct_literal(value),
Expression::Binary(binary) => self.reconstruct_binary(binary),
Expression::Call(call) => self.reconstruct_call(call),
Expression::CircuitInit(circuit) => self.reconstruct_circuit_init(circuit),
Expression::Unary(unary) => self.reconstruct_unary(unary),
Expression::Ternary(ternary) => self.reconstruct_ternary(ternary),
Expression::Err(err) => self.reconstruct_err(err),
}
}
fn reconstruct_identifier(&mut self, input: Identifier) -> (Expression, Self::AdditionalOutput) {
(Expression::Identifier(input), Default::default())
}
fn reconstruct_literal(&mut self, input: LiteralExpression) -> (Expression, Self::AdditionalOutput) {
(Expression::Literal(input), Default::default())
}
fn reconstruct_access(&mut self, input: AccessExpression) -> (Expression, Self::AdditionalOutput) {
(Expression::Access(input), Default::default())
}
fn reconstruct_circuit_init(&mut self, input: CircuitInitExpression) -> (Expression, Self::AdditionalOutput) {
(Expression::CircuitInit(input), Default::default())
}
fn reconstruct_binary(&mut self, input: BinaryExpression) -> (Expression, Self::AdditionalOutput) {
(
Expression::Binary(BinaryExpression {
left: Box::new(self.reconstruct_expression(*input.left).0),
right: Box::new(self.reconstruct_expression(*input.right).0),
op: input.op,
span: input.span,
}),
Default::default(),
)
}
fn reconstruct_unary(&mut self, input: UnaryExpression) -> (Expression, Self::AdditionalOutput) {
(
Expression::Unary(UnaryExpression {
receiver: Box::new(self.reconstruct_expression(*input.receiver).0),
op: input.op,
span: input.span,
}),
Default::default(),
)
}
fn reconstruct_ternary(&mut self, input: TernaryExpression) -> (Expression, Self::AdditionalOutput) {
(
Expression::Ternary(TernaryExpression {
condition: Box::new(self.reconstruct_expression(*input.condition).0),
if_true: Box::new(self.reconstruct_expression(*input.if_true).0),
if_false: Box::new(self.reconstruct_expression(*input.if_false).0),
span: input.span,
}),
Default::default(),
)
}
fn reconstruct_call(&mut self, input: CallExpression) -> (Expression, Self::AdditionalOutput) {
(
Expression::Call(CallExpression {
function: Box::new(self.reconstruct_expression(*input.function).0),
arguments: input
.arguments
.into_iter()
.map(|arg| self.reconstruct_expression(arg).0)
.collect(),
span: input.span,
}),
Default::default(),
)
}
fn reconstruct_err(&mut self, input: ErrExpression) -> (Expression, Self::AdditionalOutput) {
(Expression::Err(input), Default::default())
}
}
/// A Reconstructor trait for statements in the AST.
pub trait StatementReconstructor: ExpressionReconstructor {
fn reconstruct_statement(&mut self, input: Statement) -> Statement {
match input {
Statement::Return(stmt) => self.reconstruct_return(stmt),
Statement::Definition(stmt) => self.reconstruct_definition(stmt),
Statement::Assign(stmt) => self.reconstruct_assign(*stmt),
Statement::Conditional(stmt) => self.reconstruct_conditional(stmt),
Statement::Iteration(stmt) => self.reconstruct_iteration(*stmt),
Statement::Console(stmt) => self.reconstruct_console(stmt),
Statement::Block(stmt) => Statement::Block(self.reconstruct_block(stmt)),
}
}
fn reconstruct_return(&mut self, input: ReturnStatement) -> Statement {
Statement::Return(ReturnStatement {
expression: self.reconstruct_expression(input.expression).0,
span: input.span,
})
}
fn reconstruct_definition(&mut self, input: DefinitionStatement) -> Statement {
Statement::Definition(DefinitionStatement {
declaration_type: input.declaration_type,
variable_names: input.variable_names.clone(),
type_: input.type_,
value: self.reconstruct_expression(input.value).0,
span: input.span,
})
}
fn reconstruct_assign(&mut self, input: AssignStatement) -> Statement {
Statement::Assign(Box::new(AssignStatement {
operation: input.operation,
place: input.place,
value: self.reconstruct_expression(input.value).0,
span: input.span,
}))
}
fn reconstruct_conditional(&mut self, input: ConditionalStatement) -> Statement {
Statement::Conditional(ConditionalStatement {
condition: self.reconstruct_expression(input.condition).0,
block: self.reconstruct_block(input.block),
next: input.next.map(|n| Box::new(self.reconstruct_statement(*n))),
span: input.span,
})
}
fn reconstruct_iteration(&mut self, input: IterationStatement) -> Statement {
Statement::Iteration(Box::new(IterationStatement {
variable: input.variable,
type_: input.type_,
start: self.reconstruct_expression(input.start).0,
stop: self.reconstruct_expression(input.stop).0,
block: self.reconstruct_block(input.block),
inclusive: input.inclusive,
span: input.span,
}))
}
fn reconstruct_console(&mut self, input: ConsoleStatement) -> Statement {
Statement::Console(ConsoleStatement {
function: match input.function {
ConsoleFunction::Assert(expr) => ConsoleFunction::Assert(self.reconstruct_expression(expr).0),
ConsoleFunction::Error(fmt) => ConsoleFunction::Error(ConsoleArgs {
string: fmt.string,
parameters: fmt
.parameters
.into_iter()
.map(|p| self.reconstruct_expression(p).0)
.collect(),
span: fmt.span,
}),
ConsoleFunction::Log(fmt) => ConsoleFunction::Log(ConsoleArgs {
string: fmt.string,
parameters: fmt
.parameters
.into_iter()
.map(|p| self.reconstruct_expression(p).0)
.collect(),
span: fmt.span,
}),
},
span: input.span,
})
}
fn reconstruct_block(&mut self, input: Block) -> Block {
Block {
statements: input
.statements
.into_iter()
.map(|s| self.reconstruct_statement(s))
.collect(),
span: input.span,
}
}
}
/// A Reconstructor trait for the program represented by the AST.
pub trait ProgramReconstructor: StatementReconstructor {
fn reconstruct_program(&mut self, input: Program) -> Program {
Program {
name: input.name,
expected_input: input.expected_input,
functions: input
.functions
.into_iter()
.map(|(i, f)| (i, self.reconstruct_function(f)))
.collect(),
circuits: input
.circuits
.into_iter()
.map(|(i, c)| (i, self.reconstruct_circuit(c)))
.collect(),
}
}
fn reconstruct_function(&mut self, input: Function) -> Function {
Function {
identifier: input.identifier,
input: input.input,
output: input.output,
core_mapping: input.core_mapping,
block: self.reconstruct_block(input.block),
span: input.span,
}
}
fn reconstruct_circuit(&mut self, input: Circuit) -> Circuit {
input
}
}

View File

@ -14,107 +14,156 @@
// 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/>.
//! This module contains Visitor traits for the AST.
//! This module contains Visitor trait implementations for the AST.
//! It implements default methods for each node to be made
//! given the type of node its visiting.
use crate::*;
pub enum VisitResult {
VisitChildren,
SkipChildren,
}
impl Default for VisitResult {
fn default() -> Self {
VisitResult::VisitChildren
}
}
/// A Visitor trait for expressions in the AST.
pub trait ExpressionVisitor<'a> {
fn visit_expression(&mut self, _input: &'a Expression) -> VisitResult {
type AdditionalInput: Default;
type Output: Default;
fn visit_expression(&mut self, input: &'a Expression, additional: &Self::AdditionalInput) -> Self::Output {
match input {
Expression::Access(expr) => self.visit_access(expr, additional),
Expression::CircuitInit(expr) => self.visit_circuit_init(expr, additional),
Expression::Identifier(expr) => self.visit_identifier(expr, additional),
Expression::Literal(expr) => self.visit_literal(expr, additional),
Expression::Binary(expr) => self.visit_binary(expr, additional),
Expression::Unary(expr) => self.visit_unary(expr, additional),
Expression::Ternary(expr) => self.visit_ternary(expr, additional),
Expression::Call(expr) => self.visit_call(expr, additional),
Expression::Err(expr) => self.visit_err(expr, additional),
}
}
fn visit_access(&mut self, _input: &'a AccessExpression, _additional: &Self::AdditionalInput) -> Self::Output {
Default::default()
}
fn visit_access(&mut self, _input: &'a AccessExpression) -> VisitResult {
fn visit_circuit_init(
&mut self,
_input: &'a CircuitInitExpression,
_additional: &Self::AdditionalInput,
) -> Self::Output {
Default::default()
}
fn visit_binary(&mut self, _input: &'a BinaryExpression) -> VisitResult {
fn visit_identifier(&mut self, _input: &'a Identifier, _additional: &Self::AdditionalInput) -> Self::Output {
Default::default()
}
fn visit_literal(&mut self, _input: &'a LiteralExpression) -> VisitResult {
fn visit_literal(&mut self, _input: &'a LiteralExpression, _additional: &Self::AdditionalInput) -> Self::Output {
Default::default()
}
fn visit_call(&mut self, _input: &'a CallExpression) -> VisitResult {
fn visit_binary(&mut self, input: &'a BinaryExpression, additional: &Self::AdditionalInput) -> Self::Output {
self.visit_expression(&input.left, additional);
self.visit_expression(&input.right, additional);
Default::default()
}
fn visit_circuit_init(&mut self, _input: &'a CircuitInitExpression) -> VisitResult {
fn visit_unary(&mut self, input: &'a UnaryExpression, additional: &Self::AdditionalInput) -> Self::Output {
self.visit_expression(&input.receiver, additional);
Default::default()
}
fn visit_err(&mut self, _input: &'a ErrExpression) -> VisitResult {
fn visit_ternary(&mut self, input: &'a TernaryExpression, additional: &Self::AdditionalInput) -> Self::Output {
self.visit_expression(&input.condition, additional);
self.visit_expression(&input.if_true, additional);
self.visit_expression(&input.if_false, additional);
Default::default()
}
fn visit_identifier(&mut self, _input: &'a Identifier) -> VisitResult {
fn visit_call(&mut self, input: &'a CallExpression, additional: &Self::AdditionalInput) -> Self::Output {
input.arguments.iter().for_each(|expr| {
self.visit_expression(expr, additional);
});
Default::default()
}
fn visit_ternary(&mut self, _input: &'a TernaryExpression) -> VisitResult {
Default::default()
}
fn visit_unary(&mut self, _input: &'a UnaryExpression) -> VisitResult {
fn visit_err(&mut self, _input: &'a ErrExpression, _additional: &Self::AdditionalInput) -> Self::Output {
Default::default()
}
}
pub trait StatementVisitor<'a> {
fn visit_statement(&mut self, _input: &'a Statement) -> VisitResult {
Default::default()
/// A Visitor trait for statements in the AST.
pub trait StatementVisitor<'a>: ExpressionVisitor<'a> {
fn visit_statement(&mut self, input: &'a Statement) {
match input {
Statement::Return(stmt) => self.visit_return(stmt),
Statement::Definition(stmt) => self.visit_definition(stmt),
Statement::Assign(stmt) => self.visit_assign(stmt),
Statement::Conditional(stmt) => self.visit_conditional(stmt),
Statement::Iteration(stmt) => self.visit_iteration(stmt),
Statement::Console(stmt) => self.visit_console(stmt),
Statement::Block(stmt) => self.visit_block(stmt),
}
}
fn visit_return(&mut self, _input: &'a ReturnStatement) -> VisitResult {
Default::default()
fn visit_return(&mut self, input: &'a ReturnStatement) {
self.visit_expression(&input.expression, &Default::default());
}
fn visit_definition(&mut self, _input: &'a DefinitionStatement) -> VisitResult {
Default::default()
fn visit_definition(&mut self, input: &'a DefinitionStatement) {
self.visit_expression(&input.value, &Default::default());
}
fn visit_assign(&mut self, _input: &'a AssignStatement) -> VisitResult {
Default::default()
fn visit_assign(&mut self, input: &'a AssignStatement) {
self.visit_expression(&input.value, &Default::default());
}
fn visit_conditional(&mut self, _input: &'a ConditionalStatement) -> VisitResult {
Default::default()
fn visit_conditional(&mut self, input: &'a ConditionalStatement) {
self.visit_expression(&input.condition, &Default::default());
self.visit_block(&input.block);
if let Some(stmt) = input.next.as_ref() {
self.visit_statement(stmt);
}
}
fn visit_iteration(&mut self, _input: &'a IterationStatement) -> VisitResult {
Default::default()
fn visit_iteration(&mut self, input: &'a IterationStatement) {
self.visit_expression(&input.start, &Default::default());
self.visit_expression(&input.stop, &Default::default());
self.visit_block(&input.block);
}
fn visit_console(&mut self, _input: &'a ConsoleStatement) -> VisitResult {
Default::default()
fn visit_console(&mut self, input: &'a ConsoleStatement) {
match &input.function {
ConsoleFunction::Assert(expr) => {
self.visit_expression(expr, &Default::default());
}
ConsoleFunction::Error(fmt) | ConsoleFunction::Log(fmt) => {
fmt.parameters.iter().for_each(|expr| {
self.visit_expression(expr, &Default::default());
});
}
};
}
fn visit_block(&mut self, _input: &'a Block) -> VisitResult {
Default::default()
fn visit_block(&mut self, input: &'a Block) {
input.statements.iter().for_each(|stmt| self.visit_statement(stmt));
}
}
pub trait ProgramVisitor<'a> {
fn visit_program(&mut self, _input: &'a Program) -> VisitResult {
Default::default()
/// A Visitor trait for the program represented by the AST.
pub trait ProgramVisitor<'a>: StatementVisitor<'a> {
fn visit_program(&mut self, input: &'a Program) {
input
.functions
.values()
.for_each(|function| self.visit_function(function));
input
.circuits
.values()
.for_each(|function| self.visit_circuit(function));
}
fn visit_function(&mut self, _input: &'a Function) -> VisitResult {
Default::default()
fn visit_function(&mut self, input: &'a Function) {
self.visit_block(&input.block);
}
fn visit_circuit(&mut self, _input: &'a Circuit) -> VisitResult {
Default::default()
}
fn visit_circuit(&mut self, _input: &'a Circuit) {}
}

View File

@ -1,246 +0,0 @@
// 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/>.
//! This module contains Visitor trait implementations for the AST.
//! It implements default methods for each node to be made
//! given the type of node its visiting.
use crate::*;
pub trait VisitorDirector<'a> {
type Visitor: ExpressionVisitor<'a> + ProgramVisitor<'a> + StatementVisitor<'a>;
fn visitor(self) -> Self::Visitor;
fn visitor_ref(&mut self) -> &mut Self::Visitor;
}
pub trait ExpressionVisitorDirector<'a>: VisitorDirector<'a> {
type AdditionalInput: Default;
type Output;
fn visit_expression(&mut self, input: &'a Expression, additional: &Self::AdditionalInput) -> Option<Self::Output> {
if let VisitResult::VisitChildren = self.visitor_ref().visit_expression(input) {
match input {
Expression::Access(expr) => self.visit_access(expr, additional),
Expression::Identifier(expr) => self.visit_identifier(expr, additional),
Expression::Literal(expr) => self.visit_literal(expr, additional),
Expression::Binary(expr) => self.visit_binary(expr, additional),
Expression::Call(expr) => self.visit_call(expr, additional),
Expression::CircuitInit(expr) => self.visit_circuit_init(expr, additional),
Expression::Err(expr) => self.visit_err(expr, additional),
Expression::Ternary(expr) => self.visit_ternary(expr, additional),
Expression::Unary(expr) => self.visit_unary(expr, additional),
};
}
None
}
fn visit_identifier(&mut self, input: &'a Identifier, _additional: &Self::AdditionalInput) -> Option<Self::Output> {
self.visitor_ref().visit_identifier(input);
None
}
fn visit_literal(
&mut self,
input: &'a LiteralExpression,
_additional: &Self::AdditionalInput,
) -> Option<Self::Output> {
self.visitor_ref().visit_literal(input);
None
}
fn visit_access(
&mut self,
input: &'a AccessExpression,
additional: &Self::AdditionalInput,
) -> Option<Self::Output> {
if let VisitResult::VisitChildren = self.visitor_ref().visit_access(input) {
match input {
AccessExpression::Member(member) => return self.visit_expression(&member.inner, additional),
AccessExpression::AssociatedConstant(_member) => {}
AccessExpression::AssociatedFunction(member) => {
member.args.iter().for_each(|expr| {
self.visit_expression(expr, additional);
});
}
};
}
None
}
fn visit_binary(
&mut self,
input: &'a BinaryExpression,
additional: &Self::AdditionalInput,
) -> Option<Self::Output> {
if let VisitResult::VisitChildren = self.visitor_ref().visit_binary(input) {
self.visit_expression(&input.left, additional);
self.visit_expression(&input.right, additional);
}
None
}
fn visit_unary(&mut self, input: &'a UnaryExpression, additional: &Self::AdditionalInput) -> Option<Self::Output> {
if let VisitResult::VisitChildren = self.visitor_ref().visit_unary(input) {
self.visit_expression(&input.receiver, additional);
}
None
}
fn visit_ternary(
&mut self,
input: &'a TernaryExpression,
additional: &Self::AdditionalInput,
) -> Option<Self::Output> {
if let VisitResult::VisitChildren = self.visitor_ref().visit_ternary(input) {
self.visit_expression(&input.condition, additional);
self.visit_expression(&input.if_true, additional);
self.visit_expression(&input.if_false, additional);
}
None
}
fn visit_call(&mut self, input: &'a CallExpression, additional: &Self::AdditionalInput) -> Option<Self::Output> {
if let VisitResult::VisitChildren = self.visitor_ref().visit_call(input) {
input.arguments.iter().for_each(|expr| {
self.visit_expression(expr, additional);
});
}
None
}
fn visit_circuit_init(
&mut self,
input: &'a CircuitInitExpression,
additional: &Self::AdditionalInput,
) -> Option<Self::Output> {
if let VisitResult::VisitChildren = self.visitor_ref().visit_circuit_init(input) {
input.members.iter().for_each(|member| {
if let Some(expr) = &member.expression {
self.visit_expression(expr, additional);
}
});
}
None
}
fn visit_err(&mut self, input: &'a ErrExpression, _additional: &Self::AdditionalInput) -> Option<Self::Output> {
self.visitor_ref().visit_err(input);
None
}
}
pub trait StatementVisitorDirector<'a>: VisitorDirector<'a> + ExpressionVisitorDirector<'a> {
fn visit_statement(&mut self, input: &'a Statement) {
if let VisitResult::VisitChildren = self.visitor_ref().visit_statement(input) {
match input {
Statement::Return(stmt) => self.visit_return(stmt),
Statement::Definition(stmt) => self.visit_definition(stmt),
Statement::Assign(stmt) => self.visit_assign(stmt),
Statement::Conditional(stmt) => self.visit_conditional(stmt),
Statement::Iteration(stmt) => self.visit_iteration(stmt),
Statement::Console(stmt) => self.visit_console(stmt),
Statement::Block(stmt) => self.visit_block(stmt),
}
}
}
fn visit_return(&mut self, input: &'a ReturnStatement) {
if let VisitResult::VisitChildren = self.visitor_ref().visit_return(input) {
self.visit_expression(&input.expression, &Default::default());
}
}
fn visit_definition(&mut self, input: &'a DefinitionStatement) {
if let VisitResult::VisitChildren = self.visitor_ref().visit_definition(input) {
self.visit_expression(&input.value, &Default::default());
}
}
fn visit_assign(&mut self, input: &'a AssignStatement) {
if let VisitResult::VisitChildren = self.visitor_ref().visit_assign(input) {
self.visit_expression(&input.value, &Default::default());
}
}
fn visit_conditional(&mut self, input: &'a ConditionalStatement) {
if let VisitResult::VisitChildren = self.visitor_ref().visit_conditional(input) {
self.visit_expression(&input.condition, &Default::default());
self.visit_block(&input.block);
if let Some(stmt) = input.next.as_ref() {
self.visit_statement(stmt);
}
}
}
fn visit_iteration(&mut self, input: &'a IterationStatement) {
if let VisitResult::VisitChildren = self.visitor_ref().visit_iteration(input) {
self.visit_expression(&input.start, &Default::default());
self.visit_expression(&input.stop, &Default::default());
self.visit_block(&input.block);
}
}
fn visit_console(&mut self, input: &'a ConsoleStatement) {
if let VisitResult::VisitChildren = self.visitor_ref().visit_console(input) {
match &input.function {
ConsoleFunction::Assert(expr) => self.visit_expression(expr, &Default::default()),
ConsoleFunction::Error(fmt) | ConsoleFunction::Log(fmt) => {
fmt.parameters.iter().for_each(|expr| {
self.visit_expression(expr, &Default::default());
});
None
}
};
}
}
fn visit_block(&mut self, input: &'a Block) {
if let VisitResult::VisitChildren = self.visitor_ref().visit_block(input) {
input.statements.iter().for_each(|stmt| self.visit_statement(stmt));
}
}
}
pub trait ProgramVisitorDirector<'a>: VisitorDirector<'a> + StatementVisitorDirector<'a> {
fn visit_program(&mut self, input: &'a Program) {
if let VisitResult::VisitChildren = self.visitor_ref().visit_program(input) {
input
.functions
.values()
.for_each(|function| self.visit_function(function));
input.circuits.values().for_each(|circuit| self.visit_circuit(circuit));
}
}
fn visit_function(&mut self, input: &'a Function) {
if let VisitResult::VisitChildren = self.visitor_ref().visit_function(input) {
self.visit_block(&input.block);
}
}
fn visit_circuit(&mut self, input: &'a Circuit) {
if let VisitResult::VisitChildren = self.visitor_ref().visit_circuit(input) {
input.members.iter().for_each(|member| {
match member {
CircuitMember::CircuitVariable(_, _) => {}
};
})
}
}
}

View File

@ -36,22 +36,23 @@ impl<'a> CreateSymbolTable<'a> {
}
}
impl<'a> ExpressionVisitor<'a> for CreateSymbolTable<'a> {}
impl<'a> ExpressionVisitor<'a> for CreateSymbolTable<'a> {
type AdditionalInput = ();
type Output = ();
}
impl<'a> StatementVisitor<'a> for CreateSymbolTable<'a> {}
impl<'a> ProgramVisitor<'a> for CreateSymbolTable<'a> {
fn visit_function(&mut self, input: &'a Function) -> VisitResult {
fn visit_function(&mut self, input: &'a Function) {
if let Err(err) = self.symbol_table.insert_fn(input.name(), input) {
self.handler.emit_err(err);
}
VisitResult::SkipChildren
}
fn visit_circuit(&mut self, input: &'a Circuit) -> VisitResult {
fn visit_circuit(&mut self, input: &'a Circuit) {
if let Err(err) = self.symbol_table.insert_circuit(input.name(), input) {
self.handler.emit_err(err);
}
VisitResult::SkipChildren
}
}

View File

@ -1,53 +0,0 @@
// 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 leo_ast::{ExpressionVisitorDirector, ProgramVisitorDirector, StatementVisitorDirector, VisitorDirector};
use leo_errors::emitter::Handler;
use crate::CreateSymbolTable;
pub(crate) struct Director<'a> {
visitor: CreateSymbolTable<'a>,
}
impl<'a> Director<'a> {
pub(crate) fn new(handler: &'a Handler) -> Self {
Self {
visitor: CreateSymbolTable::new(handler),
}
}
}
impl<'a> VisitorDirector<'a> for Director<'a> {
type Visitor = CreateSymbolTable<'a>;
fn visitor(self) -> Self::Visitor {
self.visitor
}
fn visitor_ref(&mut self) -> &mut Self::Visitor {
&mut self.visitor
}
}
impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
type AdditionalInput = ();
type Output = ();
}
impl<'a> StatementVisitorDirector<'a> for Director<'a> {}
impl<'a> ProgramVisitorDirector<'a> for Director<'a> {}

View File

@ -17,9 +17,6 @@
pub mod create;
pub use create::*;
pub mod director;
use director::*;
pub mod table;
pub use table::*;
@ -31,7 +28,7 @@ pub use variable_symbol::*;
use crate::Pass;
use leo_ast::{Ast, ProgramVisitorDirector, VisitorDirector};
use leo_ast::{Ast, ProgramVisitor};
use leo_errors::{emitter::Handler, Result};
impl<'a> Pass for CreateSymbolTable<'a> {
@ -39,10 +36,10 @@ impl<'a> Pass for CreateSymbolTable<'a> {
type Output = Result<SymbolTable<'a>>;
fn do_pass((ast, handler): Self::Input) -> Self::Output {
let mut visitor = Director::new(handler);
let mut visitor = CreateSymbolTable::new(handler);
visitor.visit_program(ast.as_repr());
handler.last_err()?;
Ok(visitor.visitor().symbol_table())
Ok(visitor.symbol_table())
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,69 +0,0 @@
// 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 super::director::Director;
use crate::{Declaration, TypeChecker, VariableSymbol};
use leo_ast::*;
use leo_errors::TypeCheckerError;
use std::collections::HashSet;
impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {}
impl<'a> ProgramVisitorDirector<'a> for Director<'a> {
fn visit_function(&mut self, input: &'a Function) {
if let VisitResult::VisitChildren = self.visitor_ref().visit_function(input) {
self.visitor.has_return = false;
self.visitor.symbol_table.clear_variables();
self.visitor.parent = Some(input.name());
input.input.iter().for_each(|i| {
let input_var = i.get_variable();
self.visitor.check_ident_type(&Some(input_var.type_));
// Check for conflicting variable names.
if let Err(err) = self.visitor.symbol_table.insert_variable(
input_var.identifier.name,
VariableSymbol {
type_: &input_var.type_,
span: input_var.identifier.span(),
declaration: Declaration::Input(input_var.mode()),
},
) {
self.visitor.handler.emit_err(err);
}
});
self.visit_block(&input.block);
if !self.visitor.has_return {
self.visitor
.handler
.emit_err(TypeCheckerError::function_has_no_return(input.name(), input.span()).into());
}
}
}
fn visit_circuit(&mut self, input: &'a Circuit) {
if let VisitResult::VisitChildren = self.visitor_ref().visit_circuit(input) {
// Check for conflicting circuit member names.
let mut used = HashSet::new();
if !input.members.iter().all(|member| used.insert(member.name())) {
self.visitor
.handler
.emit_err(TypeCheckerError::duplicate_circuit_member(input.name(), input.span()).into());
}
}
}
}

View File

@ -0,0 +1,60 @@
// 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 crate::{Declaration, TypeChecker, VariableSymbol};
use leo_ast::*;
use leo_errors::TypeCheckerError;
use std::collections::HashSet;
impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
fn visit_function(&mut self, input: &'a Function) {
self.has_return = false;
self.symbol_table.clear_variables();
self.parent = Some(input.name());
input.input.iter().for_each(|i| {
let input_var = i.get_variable();
self.check_ident_type(&Some(input_var.type_));
// Check for conflicting variable names.
if let Err(err) = self.symbol_table.insert_variable(
input_var.identifier.name,
VariableSymbol {
type_: &input_var.type_,
span: input_var.identifier.span(),
declaration: Declaration::Input(input_var.mode()),
},
) {
self.handler.emit_err(err);
}
});
self.visit_block(&input.block);
if !self.has_return {
self.handler
.emit_err(TypeCheckerError::function_has_no_return(input.name(), input.span()).into());
}
}
fn visit_circuit(&mut self, input: &'a Circuit) {
// Check for conflicting circuit member names.
let mut used = HashSet::new();
if !input.members.iter().all(|member| used.insert(member.name())) {
self.handler
.emit_err(TypeCheckerError::duplicate_circuit_member(input.name(), input.span()).into());
}
}
}

View File

@ -19,19 +19,15 @@ use leo_errors::TypeCheckerError;
use crate::{Declaration, TypeChecker, VariableSymbol};
use super::director::Director;
impl<'a> StatementVisitor<'a> for TypeChecker<'a> {}
impl<'a> StatementVisitorDirector<'a> for Director<'a> {
impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
fn visit_return(&mut self, input: &'a ReturnStatement) {
// we can safely unwrap all self.parent instances because
// statements should always have some parent block
let parent = self.visitor.parent.unwrap();
let parent = self.parent.unwrap();
let return_type = &self.visitor.symbol_table.lookup_fn(parent).map(|f| f.output);
self.visitor.check_ident_type(return_type);
self.visitor.has_return = true;
let return_type = &self.symbol_table.lookup_fn(parent).map(|f| f.output);
self.check_ident_type(return_type);
self.has_return = true;
self.visit_expression(&input.expression, return_type);
}
@ -44,11 +40,11 @@ impl<'a> StatementVisitorDirector<'a> for Director<'a> {
};
input.variable_names.iter().for_each(|v| {
self.visitor.check_ident_type(&Some(input.type_));
self.check_ident_type(&Some(input.type_));
self.visit_expression(&input.value, &Some(input.type_));
if let Err(err) = self.visitor.symbol_table.insert_variable(
if let Err(err) = self.symbol_table.insert_variable(
v.identifier.name,
VariableSymbol {
type_: &input.type_,
@ -56,7 +52,7 @@ impl<'a> StatementVisitorDirector<'a> for Director<'a> {
declaration: declaration.clone(),
},
) {
self.visitor.handler.emit_err(err);
self.handler.emit_err(err);
}
});
}
@ -65,21 +61,18 @@ impl<'a> StatementVisitorDirector<'a> for Director<'a> {
let var_name = match input.place {
Expression::Identifier(id) => id,
_ => {
self.visitor
.handler
self.handler
.emit_err(TypeCheckerError::invalid_assignment_target(input.place.span()).into());
return;
}
};
let var_type = if let Some(var) = self.visitor.symbol_table.lookup_variable(&var_name.name) {
let var_type = if let Some(var) = self.symbol_table.lookup_variable(&var_name.name) {
match &var.declaration {
Declaration::Const => self
.visitor
.handler
.emit_err(TypeCheckerError::cannont_assign_to_const_var(var_name, var.span).into()),
Declaration::Input(ParamMode::Const) => self
.visitor
.handler
.emit_err(TypeCheckerError::cannont_assign_to_const_input(var_name, var.span).into()),
_ => {}
@ -87,15 +80,14 @@ impl<'a> StatementVisitorDirector<'a> for Director<'a> {
Some(*var.type_)
} else {
self.visitor
.handler
self.handler
.emit_err(TypeCheckerError::unknown_sym("variable", var_name.name, var_name.span).into());
None
};
if var_type.is_some() {
self.visitor.check_ident_type(&var_type);
self.check_ident_type(&var_type);
self.visit_expression(&input.value, &var_type);
}
}
@ -109,7 +101,7 @@ impl<'a> StatementVisitorDirector<'a> for Director<'a> {
}
fn visit_iteration(&mut self, input: &'a IterationStatement) {
if let Err(err) = self.visitor.symbol_table.insert_variable(
if let Err(err) = self.symbol_table.insert_variable(
input.variable.name,
VariableSymbol {
type_: &input.type_,
@ -117,11 +109,11 @@ impl<'a> StatementVisitorDirector<'a> for Director<'a> {
declaration: Declaration::Const,
},
) {
self.visitor.handler.emit_err(err);
self.handler.emit_err(err);
}
let iter_type = &Some(input.type_);
self.visitor.check_ident_type(iter_type);
self.check_ident_type(iter_type);
self.visit_expression(&input.start, iter_type);
self.visit_expression(&input.stop, iter_type);
}
@ -139,7 +131,7 @@ impl<'a> StatementVisitorDirector<'a> for Director<'a> {
fn visit_block(&mut self, input: &'a Block) {
// creates a new sub-scope since we are in a block.
self.visitor.symbol_table.push_variable_scope();
self.symbol_table.push_variable_scope();
input.statements.iter().for_each(|stmt| {
match stmt {
Statement::Return(stmt) => self.visit_return(stmt),
@ -151,6 +143,6 @@ impl<'a> StatementVisitorDirector<'a> for Director<'a> {
Statement::Block(stmt) => self.visit_block(stmt),
};
});
self.visitor.symbol_table.pop_variable_scope();
self.symbol_table.pop_variable_scope();
}
}

View File

@ -1,44 +0,0 @@
// 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 leo_ast::*;
use leo_errors::emitter::Handler;
use crate::{SymbolTable, TypeChecker};
pub(crate) struct Director<'a> {
pub(crate) visitor: TypeChecker<'a>,
}
impl<'a> Director<'a> {
pub(crate) fn new(symbol_table: &'a mut SymbolTable<'a>, handler: &'a Handler) -> Self {
Self {
visitor: TypeChecker::new(symbol_table, handler),
}
}
}
impl<'a> VisitorDirector<'a> for Director<'a> {
type Visitor = TypeChecker<'a>;
fn visitor(self) -> Self::Visitor {
self.visitor
}
fn visitor_ref(&mut self) -> &mut Self::Visitor {
&mut self.visitor
}
}

View File

@ -17,8 +17,8 @@
pub mod check_expressions;
pub use check_expressions::*;
pub mod check_file;
pub use check_file::*;
pub mod check_program;
pub use check_program::*;
pub mod check_statements;
pub use check_statements::*;
@ -26,12 +26,9 @@ pub use check_statements::*;
pub mod checker;
pub use checker::*;
pub mod director;
use director::*;
use crate::{Pass, SymbolTable};
use leo_ast::{Ast, ProgramVisitorDirector};
use leo_ast::{Ast, ProgramVisitor};
use leo_errors::{emitter::Handler, Result};
impl<'a> Pass for TypeChecker<'a> {
@ -39,7 +36,7 @@ impl<'a> Pass for TypeChecker<'a> {
type Output = Result<()>;
fn do_pass((ast, symbol_table, handler): Self::Input) -> Self::Output {
let mut visitor = Director::new(symbol_table, handler);
let mut visitor = TypeChecker::new(symbol_table, handler);
visitor.visit_program(ast.as_repr());
handler.last_err()?;