mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-11-23 15:15:47 +03:00
impl dynamic checks for core packages
This commit is contained in:
parent
54bf6ca42d
commit
9933b8e336
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -1415,6 +1415,7 @@ name = "leo-static-check"
|
||||
version = "1.0.3"
|
||||
dependencies = [
|
||||
"leo-ast",
|
||||
"leo-core",
|
||||
"leo-imports",
|
||||
"leo-typed",
|
||||
"serde",
|
||||
|
@ -162,15 +162,14 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
||||
let typed_tree = LeoTypedAst::new(&package_name, &ast);
|
||||
|
||||
self.program = typed_tree.into_repr();
|
||||
self.imported_programs = ImportParser::parse(&self.program)?;
|
||||
|
||||
// Run static check on program.
|
||||
let symbol_table = StaticCheck::run(&self.program, &self.program_input)?;
|
||||
let symbol_table = StaticCheck::run(&self.program, &self.program_input, &self.imported_programs)?;
|
||||
|
||||
// Run dynamic check on program.
|
||||
DynamicCheck::run(&self.program, symbol_table)?;
|
||||
|
||||
self.imported_programs = ImportParser::parse(&self.program)?;
|
||||
|
||||
tracing::debug!("Program parsing complete\n{:#?}", self.program);
|
||||
|
||||
Ok(())
|
||||
|
@ -27,13 +27,10 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
import: &Import,
|
||||
imported_programs: &ImportParser,
|
||||
) -> Result<(), ImportError> {
|
||||
// Fetch core dependencies
|
||||
let core_dependency = imported_programs
|
||||
.core_packages()
|
||||
.iter()
|
||||
.find(|package| import.package.eq(package));
|
||||
// Fetch core packages
|
||||
let core_package = imported_programs.get_core_package(&import.package);
|
||||
|
||||
if let Some(package) = core_dependency {
|
||||
if let Some(package) = core_package {
|
||||
self.store_core_package(scope.clone(), package.clone())?;
|
||||
|
||||
return Ok(());
|
||||
@ -42,17 +39,17 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
// Fetch dependencies for the current import
|
||||
let imported_symbols = ImportedSymbols::from(import);
|
||||
|
||||
for (package, symbol) in imported_symbols.symbols {
|
||||
for (name, symbol) in imported_symbols.symbols {
|
||||
// Find imported program
|
||||
let program = imported_programs
|
||||
.get_import(&package)
|
||||
.get_import(&name)
|
||||
.ok_or(ImportError::unknown_package(import.package.name.clone()))?;
|
||||
|
||||
// Parse imported program
|
||||
self.store_definitions(program.clone(), imported_programs)?;
|
||||
|
||||
// Store the imported symbol
|
||||
self.store_symbol(scope.clone(), package, &symbol, program)?;
|
||||
self.store_symbol(scope.clone(), name, &symbol, program)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -90,6 +90,15 @@ impl ImportParser {
|
||||
self.imports.get(file_name)
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns a reference to the core package corresponding to the given package.
|
||||
///
|
||||
pub fn get_core_package(&self, package: &Package) -> Option<&Package> {
|
||||
self.core_packages()
|
||||
.iter()
|
||||
.find(|core_package| core_package.eq(&package))
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns a reference to the vector of core packages.
|
||||
///
|
||||
|
@ -21,6 +21,10 @@ edition = "2018"
|
||||
path = "../ast"
|
||||
version = "1.0.3"
|
||||
|
||||
[dependencies.leo-core]
|
||||
path = "../core"
|
||||
version = "1.0.3"
|
||||
|
||||
[dependencies.leo-imports]
|
||||
path = "../imports"
|
||||
version = "1.0.3"
|
||||
|
@ -15,6 +15,7 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::TypeError;
|
||||
use leo_core::{CorePackageListError, LeoCoreError};
|
||||
use leo_typed::{Error as FormattedError, Identifier, Span};
|
||||
|
||||
use std::path::PathBuf;
|
||||
@ -22,9 +23,15 @@ use std::path::PathBuf;
|
||||
/// Errors encountered when tracking variable, function, and circuit names in a program.
|
||||
#[derive(Debug, Error)]
|
||||
pub enum SymbolTableError {
|
||||
#[error("{}", _0)]
|
||||
CorePackageListError(#[from] CorePackageListError),
|
||||
|
||||
#[error("{}", _0)]
|
||||
Error(#[from] FormattedError),
|
||||
|
||||
#[error("{}", _0)]
|
||||
LeoCoreError(#[from] LeoCoreError),
|
||||
|
||||
#[error("{}", _0)]
|
||||
TypeError(#[from] TypeError),
|
||||
}
|
||||
@ -35,7 +42,9 @@ impl SymbolTableError {
|
||||
///
|
||||
pub fn set_path(&mut self, path: PathBuf) {
|
||||
match self {
|
||||
SymbolTableError::CorePackageListError(error) => error.set_path(path),
|
||||
SymbolTableError::Error(error) => error.set_path(path),
|
||||
SymbolTableError::LeoCoreError(error) => error.set_path(path),
|
||||
SymbolTableError::TypeError(error) => error.set_path(path),
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{StaticCheckError, SymbolTable};
|
||||
use leo_imports::ImportParser;
|
||||
use leo_typed::{Input, Program};
|
||||
|
||||
/// Performs a static type check over a program.
|
||||
@ -35,14 +36,21 @@ impl StaticCheck {
|
||||
///
|
||||
/// Returns a new `SymbolTable` from a given program.
|
||||
///
|
||||
pub fn run(program: &Program, input: &Input) -> Result<SymbolTable, StaticCheckError> {
|
||||
pub fn run(
|
||||
program: &Program,
|
||||
input: &Input,
|
||||
import_parser: &ImportParser,
|
||||
) -> Result<SymbolTable, StaticCheckError> {
|
||||
let mut check = Self::new();
|
||||
|
||||
// Load program input types.
|
||||
check.load_input(input)?;
|
||||
check.insert_input(input)?;
|
||||
|
||||
// // Load the program imports into the symbol table.
|
||||
// check.insert_imports()?;
|
||||
|
||||
// Run pass one checks
|
||||
check.pass_one(program)?;
|
||||
check.pass_one(program, import_parser)?;
|
||||
|
||||
// Run pass two checks
|
||||
check.pass_two(program)?;
|
||||
@ -51,21 +59,29 @@ impl StaticCheck {
|
||||
}
|
||||
|
||||
///
|
||||
/// Loads the program input types into the symbol table.
|
||||
/// Inserts the program input types into the symbol table.
|
||||
///
|
||||
pub fn load_input(&mut self, input: &Input) -> Result<(), StaticCheckError> {
|
||||
pub fn insert_input(&mut self, input: &Input) -> Result<(), StaticCheckError> {
|
||||
self.table
|
||||
.load_input(input)
|
||||
.insert_input(input)
|
||||
.map_err(|err| StaticCheckError::SymbolTableError(err))
|
||||
}
|
||||
|
||||
// ///
|
||||
// /// Inserts the program imports into the symbol table.
|
||||
// ///
|
||||
// pub fn insert_imports(&mut self, imports: &ImportParser) -> Result<(), StaticCheckError> {}
|
||||
|
||||
///
|
||||
/// Checks for duplicate circuit and function names given an unresolved program.
|
||||
///
|
||||
/// If a circuit or function name has no duplicates, then it is inserted into the symbol table.
|
||||
/// Variables defined later in the unresolved program cannot have the same name.
|
||||
///
|
||||
pub fn pass_one(&mut self, program: &Program) -> Result<(), StaticCheckError> {
|
||||
pub fn pass_one(&mut self, program: &Program, import_parser: &ImportParser) -> Result<(), StaticCheckError> {
|
||||
// Check unresolved program import names.
|
||||
self.table.check_imports(&program.imports, import_parser)?;
|
||||
|
||||
// Check unresolved program circuit names.
|
||||
self.table.check_duplicate_circuits(&program.circuits)?;
|
||||
|
||||
|
@ -15,9 +15,10 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{CircuitType, CircuitVariableType, FunctionType, ParameterType, SymbolTableError};
|
||||
use leo_typed::{Circuit, Function, Identifier, Input};
|
||||
|
||||
use leo_core::CorePackageList;
|
||||
use leo_imports::ImportParser;
|
||||
use leo_typed::{Circuit, Function, Identifier, Import, Input, Package};
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub const INPUT_VARIABLE_NAME: &str = "input";
|
||||
@ -149,9 +150,13 @@ impl SymbolTable {
|
||||
}
|
||||
|
||||
///
|
||||
/// Loads function input types into symbol table.
|
||||
/// Inserts function input types into symbol table.
|
||||
///
|
||||
pub fn load_input(&mut self, input: &Input) -> Result<(), SymbolTableError> {
|
||||
/// Creates a new `CircuitType` to represent the input values.
|
||||
/// The type contains register, record, state, and state leaf circuit variables.
|
||||
/// This allows easy access to input types using dot syntax: `input.register.r0`.
|
||||
///
|
||||
pub fn insert_input(&mut self, input: &Input) -> Result<(), SymbolTableError> {
|
||||
// Get values for each input section.
|
||||
let registers_values = input.get_registers().values();
|
||||
let record_values = input.get_record().values();
|
||||
@ -194,13 +199,77 @@ impl SymbolTable {
|
||||
///
|
||||
/// No type resolution performed at this step.
|
||||
///
|
||||
pub fn insert_imports(&mut self, _imports: ImportParser) {}
|
||||
// pub fn insert_imports(&mut self, imports: ImportParser) -> Result<(), SymbolTableError> {
|
||||
// // Iterate over each imported program.
|
||||
//
|
||||
// // Store separate symbol table for each program.
|
||||
//
|
||||
// //
|
||||
// }
|
||||
|
||||
///
|
||||
/// Checks for duplicate circuit names given a hashmap of unresolved circuits.
|
||||
/// Inserts core package name and type information into the symbol table.
|
||||
///
|
||||
pub fn insert_core_package(&mut self, package: &Package) -> Result<(), SymbolTableError> {
|
||||
// Create list of imported core packages.
|
||||
let list = CorePackageList::from_package_access(package.access.to_owned())?;
|
||||
|
||||
// Fetch core package symbols from `leo-core`.
|
||||
let symbol_list = list.to_symbols()?;
|
||||
|
||||
// Insert name and type information for each core package symbol.
|
||||
for (name, circuit) in symbol_list.symbols() {
|
||||
// Store name of symbol.
|
||||
self.insert_name(name, ParameterType::from(circuit.clone()));
|
||||
|
||||
// Create new circuit type for symbol.
|
||||
let circuit_type = CircuitType::new(&self, circuit)?;
|
||||
|
||||
// Insert circuit type of symbol.
|
||||
self.insert_circuit(circuit_type.identifier.clone(), circuit_type);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// Checks that all given imported names exist in the list of imported programs.
|
||||
///
|
||||
/// Additionally checks for duplicate imported names in the given vector of imports.
|
||||
/// Types defined later in the program cannot have the same name.
|
||||
///
|
||||
pub fn check_imports(
|
||||
&mut self,
|
||||
imports: &Vec<Import>,
|
||||
import_parser: &ImportParser,
|
||||
) -> Result<(), SymbolTableError> {
|
||||
// Iterate over imported names.
|
||||
for import in imports.iter() {
|
||||
// Check if the import name exists as core package.
|
||||
let core_package = import_parser.get_core_package(&import.package);
|
||||
|
||||
// If the core package exists, then attempt to insert the import into the symbol table.
|
||||
match core_package {
|
||||
Some(package) => self.insert_core_package(package)?,
|
||||
None => {
|
||||
// Check if the import name exists in the import parser.
|
||||
|
||||
// Attempt to insert the imported name into the symbol table.
|
||||
|
||||
// Check that the imported name is unique.
|
||||
unimplemented!("normal imports not supported yet")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// Checks for duplicate circuit names given a hashmap of circuits.
|
||||
///
|
||||
/// If a circuit name has no duplicates, then it is inserted into the symbol table.
|
||||
/// Variables defined later in the unresolved program cannot have the same name.
|
||||
/// Types defined later in the program cannot have the same name.
|
||||
///
|
||||
pub fn check_duplicate_circuits(
|
||||
&mut self,
|
||||
@ -224,10 +293,10 @@ impl SymbolTable {
|
||||
}
|
||||
|
||||
///
|
||||
/// Checks for duplicate function names given a hashmap of unresolved functions.
|
||||
/// Checks for duplicate function names given a hashmap of functions.
|
||||
///
|
||||
/// If a function name has no duplicates, then it is inserted into the symbol table.
|
||||
/// Variables defined later in the unresolved program cannot have the same name.
|
||||
/// Types defined later in the program cannot have the same name.
|
||||
///
|
||||
pub fn check_duplicate_functions(
|
||||
&mut self,
|
||||
@ -251,10 +320,10 @@ impl SymbolTable {
|
||||
}
|
||||
|
||||
///
|
||||
/// Checks for unknown types in a circuit given a hashmap of unresolved circuits.
|
||||
/// Checks for unknown types in a circuit given a hashmap of circuits.
|
||||
///
|
||||
/// If a circuit definition only contains known types, then it is inserted into the
|
||||
/// symbol table. Variables defined later in the unresolved program can lookup the definition
|
||||
/// symbol table. Variables defined later in the program can lookup the definition
|
||||
/// and refer to its expected types
|
||||
///
|
||||
pub fn check_unknown_types_circuits(
|
||||
@ -263,10 +332,10 @@ impl SymbolTable {
|
||||
) -> Result<(), SymbolTableError> {
|
||||
// Iterate over circuit names and definitions.
|
||||
for (_, circuit) in circuits.iter() {
|
||||
// Get the identifier of the unresolved circuit.
|
||||
// Get the identifier of the circuit.
|
||||
let identifier = circuit.circuit_name.clone();
|
||||
|
||||
// Resolve unknown types in the unresolved circuit definition.
|
||||
// Resolve unknown types in the circuit definition.
|
||||
let circuit_type = CircuitType::new(self, circuit.clone())?;
|
||||
|
||||
// Attempt to insert the circuit definition into the symbol table.
|
||||
@ -277,10 +346,10 @@ impl SymbolTable {
|
||||
}
|
||||
|
||||
///
|
||||
/// Checks for unknown types in a function given a hashmap of unresolved functions.
|
||||
/// Checks for unknown types in a function given a hashmap of functions.
|
||||
///
|
||||
/// If a function definition only contains known types, then it is inserted into the
|
||||
/// symbol table. Variables defined later in the unresolved program can lookup the definition
|
||||
/// symbol table. Variables defined later in the program can lookup the definition
|
||||
/// and refer to its expected types
|
||||
///
|
||||
pub fn check_unknown_types_functions(
|
||||
@ -289,10 +358,10 @@ impl SymbolTable {
|
||||
) -> Result<(), SymbolTableError> {
|
||||
// Iterate over function names and definitions.
|
||||
for (_, function) in functions.iter() {
|
||||
// Get the identifier of the unresolved function.
|
||||
// Get the identifier of the function.
|
||||
let identifier = function.identifier.clone();
|
||||
|
||||
// Resolve unknown types in the unresolved function definition.
|
||||
// Resolve unknown types in the function definition.
|
||||
let function_type = FunctionType::new(&self, function.clone())?;
|
||||
|
||||
// Attempt to insert the function definition into the symbol table.
|
||||
|
Loading…
Reference in New Issue
Block a user