use crate::{Frame, Scope, TypeInferenceError};
use leo_ast::{Circuit, CircuitMember, Function, Program};
use leo_symbol_table::SymbolTable;
pub struct TypeInference {
table: SymbolTable,
frames: Vec<Frame>,
}
impl TypeInference {
#[allow(clippy::new_ret_no_self)]
pub fn new(program: &Program, symbol_table: SymbolTable) -> Result<(), TypeInferenceError> {
let mut type_inference = Self {
table: symbol_table,
frames: Vec::new(),
};
type_inference.parse_program(program)?;
type_inference.check()
}
fn parse_program(&mut self, program: &Program) -> Result<(), TypeInferenceError> {
self.parse_circuits(program.circuits.iter().map(|(_identifier, circuit)| circuit))?;
self.parse_functions(program.functions.iter().map(|(_identifier, function)| function))
}
fn parse_circuits<'a>(&mut self, circuits: impl Iterator<Item = &'a Circuit>) -> Result<(), TypeInferenceError> {
for circuit in circuits {
self.parse_circuit(circuit)?;
}
Ok(())
}
fn parse_circuit(&mut self, circuit: &Circuit) -> Result<(), TypeInferenceError> {
let name = &circuit.circuit_name.name;
let circuit_type = self.table.get_circuit_type(name).unwrap().clone();
for circuit_member in &circuit.members {
if let CircuitMember::CircuitFunction(function) = circuit_member {
let frame = Frame::new_circuit_function(
function.to_owned(),
circuit_type.clone(),
Scope::default(),
self.table.clone(),
)?;
self.frames.push(frame)
}
}
Ok(())
}
fn parse_functions<'a>(&mut self, functions: impl Iterator<Item = &'a Function>) -> Result<(), TypeInferenceError> {
for function in functions {
self.parse_function(function)?;
}
Ok(())
}
fn parse_function(&mut self, function: &Function) -> Result<(), TypeInferenceError> {
let frame = Frame::new_function(function.to_owned(), None, None, self.table.clone())?;
self.frames.push(frame);
Ok(())
}
pub fn check(self) -> Result<(), TypeInferenceError> {
for frame in self.frames {
frame.check()?;
}
Ok(())
}
}