mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-11-23 15:15:47 +03:00
add import parsing to first pass of static check
This commit is contained in:
parent
d5bc0d2b7f
commit
09d86576ea
@ -165,7 +165,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
||||
self.imported_programs = ImportParser::parse(&self.program)?;
|
||||
|
||||
// Run static check on program.
|
||||
let symbol_table = StaticCheck::run(&self.program, &self.program_input, &self.imported_programs)?;
|
||||
let symbol_table = StaticCheck::run_with_input(&self.program, &self.imported_programs, &self.program_input)?;
|
||||
|
||||
// Run dynamic check on program.
|
||||
DynamicCheck::run(&self.program, symbol_table)?;
|
||||
|
@ -14,9 +14,10 @@
|
||||
// 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::{errors::ImportError, imported_symbols::ImportedSymbols, ConstrainedProgram, GroupType};
|
||||
use crate::{errors::ImportError, ConstrainedProgram, GroupType};
|
||||
use leo_imports::ImportParser;
|
||||
use leo_typed::Import;
|
||||
use leo_static_check::imported_symbols::ImportedSymbols;
|
||||
use leo_typed::ImportStatement;
|
||||
|
||||
use snarkos_models::curves::{Field, PrimeField};
|
||||
|
||||
@ -24,7 +25,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
pub(crate) fn store_import(
|
||||
&mut self,
|
||||
scope: String,
|
||||
import: &Import,
|
||||
import: &ImportStatement,
|
||||
imported_programs: &ImportParser,
|
||||
) -> Result<(), ImportError> {
|
||||
// Fetch core packages
|
||||
|
@ -1,55 +1,55 @@
|
||||
// Copyright (C) 2019-2020 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_typed::{Import, ImportSymbol, Package, PackageAccess};
|
||||
|
||||
/// Stores the the package file name and imported symbol from an import statement
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ImportedSymbols {
|
||||
pub symbols: Vec<(String, ImportSymbol)>,
|
||||
}
|
||||
|
||||
impl ImportedSymbols {
|
||||
fn new() -> Self {
|
||||
Self { symbols: vec![] }
|
||||
}
|
||||
|
||||
pub(crate) fn from(import: &Import) -> Self {
|
||||
let mut symbols = Self::new();
|
||||
|
||||
symbols.from_package(&import.package);
|
||||
|
||||
symbols
|
||||
}
|
||||
|
||||
fn from_package(&mut self, package: &Package) {
|
||||
self.from_package_access(package.name.name.clone(), &package.access);
|
||||
}
|
||||
|
||||
fn from_package_access(&mut self, package: String, access: &PackageAccess) {
|
||||
match access {
|
||||
PackageAccess::SubPackage(package) => self.from_package(package),
|
||||
PackageAccess::Star(span) => {
|
||||
let star = ImportSymbol::star(span);
|
||||
self.symbols.push((package, star));
|
||||
}
|
||||
PackageAccess::Symbol(symbol) => self.symbols.push((package, symbol.clone())),
|
||||
PackageAccess::Multiple(packages) => packages
|
||||
.iter()
|
||||
.for_each(|access| self.from_package_access(package.clone(), access)),
|
||||
}
|
||||
}
|
||||
}
|
||||
// // Copyright (C) 2019-2020 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_typed::{ImportStatement, ImportSymbol, Package, PackageAccess};
|
||||
//
|
||||
// /// Stores the the package file name and imported symbol from an import statement
|
||||
// #[derive(Debug)]
|
||||
// pub(crate) struct ImportedSymbols {
|
||||
// pub symbols: Vec<(String, ImportSymbol)>,
|
||||
// }
|
||||
//
|
||||
// impl ImportedSymbols {
|
||||
// fn new() -> Self {
|
||||
// Self { symbols: vec![] }
|
||||
// }
|
||||
//
|
||||
// pub(crate) fn from(import: &ImportStatement) -> Self {
|
||||
// let mut symbols = Self::new();
|
||||
//
|
||||
// symbols.from_package(&import.package);
|
||||
//
|
||||
// symbols
|
||||
// }
|
||||
//
|
||||
// fn from_package(&mut self, package: &Package) {
|
||||
// self.from_package_access(package.name.name.clone(), &package.access);
|
||||
// }
|
||||
//
|
||||
// fn from_package_access(&mut self, package: String, access: &PackageAccess) {
|
||||
// match access {
|
||||
// PackageAccess::SubPackage(package) => self.from_package(package),
|
||||
// PackageAccess::Star(span) => {
|
||||
// let star = ImportSymbol::star(span);
|
||||
// self.symbols.push((package, star));
|
||||
// }
|
||||
// PackageAccess::Symbol(symbol) => self.symbols.push((package, symbol.clone())),
|
||||
// PackageAccess::Multiple(packages) => packages
|
||||
// .iter()
|
||||
// .for_each(|access| self.from_package_access(package.clone(), access)),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
@ -21,7 +21,7 @@ pub use self::core_package::*;
|
||||
pub mod import;
|
||||
pub use self::import::*;
|
||||
|
||||
pub mod imported_symbols;
|
||||
// pub mod imported_symbols;
|
||||
|
||||
pub mod symbol;
|
||||
pub use self::symbol::*;
|
||||
|
@ -45,7 +45,7 @@ impl TestDynamicCheck {
|
||||
let program = typed.into_repr();
|
||||
|
||||
// Create static check.
|
||||
let symbol_table = StaticCheck::run(&program).unwrap();
|
||||
let symbol_table = StaticCheck::run_with_input(&program).unwrap();
|
||||
|
||||
// Create dynamic check
|
||||
let dynamic_check = DynamicCheck::new(&program, symbol_table).unwrap();
|
||||
|
@ -15,7 +15,7 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::errors::ImportParserError;
|
||||
use leo_typed::{Package, Program, Span};
|
||||
use leo_typed::{Package, Program};
|
||||
|
||||
use std::{collections::HashMap, env::current_dir};
|
||||
|
||||
@ -43,25 +43,12 @@ impl ImportParser {
|
||||
///
|
||||
/// Inserts a (file name -> program) pair into the `ImportParser`.
|
||||
///
|
||||
/// If the map did not have this file name present, `Ok()` is returned.
|
||||
/// It is okay if the imported program is already present since importing multiple symbols from
|
||||
/// the same file is allowed.
|
||||
///
|
||||
/// If the map did have this file name present, a duplicate import error is thrown.
|
||||
///
|
||||
pub(crate) fn insert_import(
|
||||
&mut self,
|
||||
file_name: String,
|
||||
program: Program,
|
||||
span: &Span,
|
||||
) -> Result<(), ImportParserError> {
|
||||
pub(crate) fn insert_import(&mut self, file_name: String, program: Program) {
|
||||
// Insert the imported program.
|
||||
let duplicate = self.imports.insert(file_name.clone(), program);
|
||||
|
||||
// Check for duplicate import name.
|
||||
if duplicate.is_some() {
|
||||
return Err(ImportParserError::duplicate_import(file_name, span.clone()));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
let _program = self.imports.insert(file_name.clone(), program);
|
||||
}
|
||||
|
||||
///
|
||||
@ -86,7 +73,7 @@ impl ImportParser {
|
||||
///
|
||||
/// Returns a reference to the program corresponding to the file name.
|
||||
///
|
||||
pub fn get_import(&self, file_name: &String) -> Option<&Program> {
|
||||
pub fn get_import(&self, file_name: &str) -> Option<&Program> {
|
||||
self.imports.get(file_name)
|
||||
}
|
||||
|
||||
|
@ -107,7 +107,7 @@ impl ImportParser {
|
||||
.unwrap(); // the file exists so these will not fail
|
||||
|
||||
// Attempt to insert the typed syntax tree for the imported package.
|
||||
self.insert_import(file_name, program, span)?;
|
||||
self.insert_import(file_name, program);
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
@ -140,7 +140,7 @@ impl ImportParser {
|
||||
.unwrap(); // the file exists so these will not fail
|
||||
|
||||
// Attempt to insert the typed syntax tree for the imported package.
|
||||
self.insert_import(file_name, program, &symbol.span)?;
|
||||
self.insert_import(file_name, program);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -14,9 +14,9 @@
|
||||
// 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::TypeError;
|
||||
use crate::{ParameterType, TypeError};
|
||||
use leo_core::{CorePackageListError, LeoCoreError};
|
||||
use leo_typed::{Error as FormattedError, Identifier, Span};
|
||||
use leo_typed::{Error as FormattedError, ImportSymbol, Program, Span};
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
@ -59,18 +59,42 @@ impl SymbolTableError {
|
||||
///
|
||||
/// Two circuits have been defined with the same name.
|
||||
///
|
||||
pub fn duplicate_circuit(identifier: Identifier, span: Span) -> Self {
|
||||
let message = format!("Duplicate circuit definition found for `{}`", identifier);
|
||||
pub fn duplicate_circuit(variable: ParameterType) -> Self {
|
||||
let message = format!("Duplicate circuit definition found for `{}`", variable.identifier);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
Self::new_from_span(message, variable.identifier.span)
|
||||
}
|
||||
|
||||
///
|
||||
/// Two functions have been defined with the same name.
|
||||
///
|
||||
pub fn duplicate_function(identifier: Identifier, span: Span) -> Self {
|
||||
let message = format!("Duplicate function definition found for `{}`", identifier);
|
||||
pub fn duplicate_function(variable: ParameterType) -> Self {
|
||||
let message = format!("Duplicate function definition found for `{}`", variable.identifier);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
Self::new_from_span(message, variable.identifier.span)
|
||||
}
|
||||
|
||||
///
|
||||
/// Attempted to access a package name that is not defined.
|
||||
///
|
||||
pub fn unknown_package(name: &str, span: &Span) -> Self {
|
||||
let message = format!(
|
||||
"Cannot find imported package `{}` in source files or import directory",
|
||||
name
|
||||
);
|
||||
|
||||
Self::new_from_span(message, span.to_owned())
|
||||
}
|
||||
|
||||
///
|
||||
/// Attempted to import a name that is not defined in the current file.
|
||||
///
|
||||
pub fn unknown_symbol(symbol: &ImportSymbol, program: &Program) -> Self {
|
||||
let message = format!(
|
||||
"Cannot find imported symbol `{}` in imported file `{}`",
|
||||
symbol, program.name
|
||||
);
|
||||
|
||||
Self::new_from_span(message, symbol.span.to_owned())
|
||||
}
|
||||
}
|
||||
|
55
static-check/src/imports/imported_symbols.rs
Normal file
55
static-check/src/imports/imported_symbols.rs
Normal file
@ -0,0 +1,55 @@
|
||||
// Copyright (C) 2019-2020 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_typed::{ImportStatement, ImportSymbol, Package, PackageAccess};
|
||||
|
||||
/// Stores the the package file name and imported symbol from an import statement
|
||||
#[derive(Debug)]
|
||||
pub struct ImportedSymbols {
|
||||
pub symbols: Vec<(String, ImportSymbol)>,
|
||||
}
|
||||
|
||||
impl ImportedSymbols {
|
||||
fn new() -> Self {
|
||||
Self { symbols: vec![] }
|
||||
}
|
||||
|
||||
pub fn from(import: &ImportStatement) -> Self {
|
||||
let mut symbols = Self::new();
|
||||
|
||||
symbols.from_package(&import.package);
|
||||
|
||||
symbols
|
||||
}
|
||||
|
||||
fn from_package(&mut self, package: &Package) {
|
||||
self.from_package_access(package.name.name.clone(), &package.access);
|
||||
}
|
||||
|
||||
fn from_package_access(&mut self, package: String, access: &PackageAccess) {
|
||||
match access {
|
||||
PackageAccess::SubPackage(package) => self.from_package(package),
|
||||
PackageAccess::Star(span) => {
|
||||
let star = ImportSymbol::star(span);
|
||||
self.symbols.push((package, star));
|
||||
}
|
||||
PackageAccess::Symbol(symbol) => self.symbols.push((package, symbol.clone())),
|
||||
PackageAccess::Multiple(packages) => packages
|
||||
.iter()
|
||||
.for_each(|access| self.from_package_access(package.clone(), access)),
|
||||
}
|
||||
}
|
||||
}
|
18
static-check/src/imports/mod.rs
Normal file
18
static-check/src/imports/mod.rs
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright (C) 2019-2020 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/>.
|
||||
|
||||
pub mod imported_symbols;
|
||||
pub use self::imported_symbols::*;
|
@ -23,6 +23,9 @@ pub use self::attributes::*;
|
||||
pub mod errors;
|
||||
pub use self::errors::*;
|
||||
|
||||
pub mod imports;
|
||||
pub use self::imports::*;
|
||||
|
||||
pub mod static_check;
|
||||
pub use self::static_check::*;
|
||||
|
||||
|
@ -34,30 +34,47 @@ impl StaticCheck {
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns a new `SymbolTable` from a given program.
|
||||
/// Returns a new `SymbolTable` from a given program and import parser.
|
||||
///
|
||||
pub fn run(
|
||||
pub fn run(program: &Program, import_parser: &ImportParser) -> Result<SymbolTable, StaticCheckError> {
|
||||
let mut check = Self::new();
|
||||
|
||||
// Run checks on program and imports.
|
||||
check.check(program, import_parser)?;
|
||||
|
||||
Ok(check.table)
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns a new `SymbolTable` from a given program, input, and import parser.
|
||||
///
|
||||
pub fn run_with_input(
|
||||
program: &Program,
|
||||
input: &Input,
|
||||
import_parser: &ImportParser,
|
||||
input: &Input,
|
||||
) -> Result<SymbolTable, StaticCheckError> {
|
||||
let mut check = Self::new();
|
||||
|
||||
// Load program input types.
|
||||
check.insert_input(input)?;
|
||||
|
||||
// // Load the program imports into the symbol table.
|
||||
// check.insert_imports()?;
|
||||
|
||||
// Run pass one checks
|
||||
check.pass_one(program, import_parser)?;
|
||||
|
||||
// Run pass two checks
|
||||
check.pass_two(program)?;
|
||||
// Run checks on program and imports.
|
||||
check.check(program, import_parser)?;
|
||||
|
||||
Ok(check.table)
|
||||
}
|
||||
|
||||
///
|
||||
/// Computes pass one and pass two checks on self.
|
||||
///
|
||||
pub fn check(&mut self, program: &Program, import_parser: &ImportParser) -> Result<(), StaticCheckError> {
|
||||
// Run pass one checks.
|
||||
self.pass_one(program, import_parser)?;
|
||||
|
||||
// Run pass two checks.
|
||||
self.pass_two(program)
|
||||
}
|
||||
|
||||
///
|
||||
/// Inserts the program input types into the symbol table.
|
||||
///
|
||||
@ -67,11 +84,6 @@ impl StaticCheck {
|
||||
.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.
|
||||
///
|
||||
@ -79,16 +91,9 @@ impl StaticCheck {
|
||||
/// Variables defined later in the unresolved program cannot have the same name.
|
||||
///
|
||||
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)?;
|
||||
|
||||
// Check unresolved program function names.
|
||||
self.table.check_duplicate_functions(&program.functions)?;
|
||||
|
||||
Ok(())
|
||||
self.table
|
||||
.check_duplicate_program(program, import_parser)
|
||||
.map_err(|err| StaticCheckError::SymbolTableError(err))
|
||||
}
|
||||
|
||||
///
|
||||
|
@ -14,10 +14,10 @@
|
||||
// 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::{CircuitType, CircuitVariableType, FunctionType, ParameterType, SymbolTableError};
|
||||
use crate::{CircuitType, CircuitVariableType, FunctionType, ImportedSymbols, ParameterType, SymbolTableError};
|
||||
use leo_core::CorePackageList;
|
||||
use leo_imports::ImportParser;
|
||||
use leo_typed::{Circuit, Function, Identifier, Import, Input, Package};
|
||||
use leo_typed::{Circuit, Function, Identifier, ImportStatement, ImportSymbol, Input, Package, Program};
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
@ -69,9 +69,36 @@ impl SymbolTable {
|
||||
/// variable type is returned.
|
||||
///
|
||||
pub fn insert_name(&mut self, name: String, variable_type: ParameterType) -> Option<ParameterType> {
|
||||
println!("name: {}", name);
|
||||
self.names.insert(name, variable_type)
|
||||
}
|
||||
|
||||
///
|
||||
/// Insert a circuit name into the symbol table from a given name and variable type.
|
||||
///
|
||||
/// Returns an error if the circuit name is a duplicate.
|
||||
///
|
||||
pub fn insert_circuit_name(&mut self, name: String, variable_type: ParameterType) -> Result<(), SymbolTableError> {
|
||||
// Check that the circuit name is unique.
|
||||
match self.insert_name(name, variable_type) {
|
||||
Some(duplicate) => Err(SymbolTableError::duplicate_circuit(duplicate)),
|
||||
None => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Insert a function name into the symbol table from a given name and variable type.
|
||||
///
|
||||
/// Returns an error if the function name is a duplicate.
|
||||
///
|
||||
pub fn insert_function_name(&mut self, name: String, variable_type: ParameterType) -> Result<(), SymbolTableError> {
|
||||
// Check that the circuit name is unique.
|
||||
match self.insert_name(name, variable_type) {
|
||||
Some(duplicate) => Err(SymbolTableError::duplicate_function(duplicate)),
|
||||
None => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Insert a circuit definition into the symbol table from a given circuit identifier and
|
||||
/// circuit type.
|
||||
@ -153,7 +180,7 @@ impl SymbolTable {
|
||||
/// Inserts function input types into symbol table.
|
||||
///
|
||||
/// Creates a new `CircuitType` to represent the input values.
|
||||
/// The type contains register, record, state, and state leaf circuit variables.
|
||||
/// The new 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> {
|
||||
@ -195,17 +222,92 @@ impl SymbolTable {
|
||||
}
|
||||
|
||||
///
|
||||
/// Inserts all imported identifiers for a given list of imported programs.
|
||||
/// Inserts the imported symbol into the symbol table if it is present in the given program.
|
||||
///
|
||||
pub fn insert_import_symbol(&mut self, symbol: ImportSymbol, program: &Program) -> Result<(), SymbolTableError> {
|
||||
// Check for import *.
|
||||
if symbol.is_star() {
|
||||
// Insert all program circuits.
|
||||
self.check_duplicate_circuits(&program.circuits)?;
|
||||
|
||||
// Insert all program functions.
|
||||
self.check_duplicate_functions(&program.functions)
|
||||
} else {
|
||||
// Check for a symbol alias.
|
||||
let identifier = symbol.alias.to_owned().unwrap_or(symbol.symbol.to_owned());
|
||||
|
||||
// Check if the imported symbol is a circuit
|
||||
let matched_circuit = program
|
||||
.circuits
|
||||
.iter()
|
||||
.find(|(circuit_name, _circuit_def)| symbol.symbol == **circuit_name);
|
||||
|
||||
match matched_circuit {
|
||||
Some((_circuit_name, circuit)) => {
|
||||
// Insert imported circuit.
|
||||
self.insert_circuit_name(identifier.to_string(), ParameterType::from(circuit.to_owned()))
|
||||
}
|
||||
None => {
|
||||
// Check if the imported symbol is a function.
|
||||
let matched_function = program
|
||||
.functions
|
||||
.iter()
|
||||
.find(|(function_name, _function)| symbol.symbol == **function_name);
|
||||
|
||||
match matched_function {
|
||||
Some((_function_name, function)) => {
|
||||
// Insert the imported function.
|
||||
self.insert_function_name(identifier.to_string(), ParameterType::from(function.to_owned()))
|
||||
}
|
||||
None => Err(SymbolTableError::unknown_symbol(&symbol, program)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Inserts one or more imported symbols for a given import statement.
|
||||
///
|
||||
/// No type resolution performed at this step.
|
||||
///
|
||||
// pub fn insert_imports(&mut self, imports: ImportParser) -> Result<(), SymbolTableError> {
|
||||
// // Iterate over each imported program.
|
||||
//
|
||||
// // Store separate symbol table for each program.
|
||||
//
|
||||
// //
|
||||
// }
|
||||
pub fn insert_import(
|
||||
&mut self,
|
||||
import: &ImportStatement,
|
||||
import_parser: &ImportParser,
|
||||
) -> Result<(), SymbolTableError> {
|
||||
// Get imported symbols from statement.
|
||||
let imported_symbols = ImportedSymbols::from(import);
|
||||
|
||||
// Import all symbols from an imported file for now.
|
||||
|
||||
// Keep track of which import files have already been checked.
|
||||
let mut checked = Vec::new();
|
||||
|
||||
// Iterate over each imported symbol.
|
||||
for (name, symbol) in imported_symbols.symbols {
|
||||
// Skip the imported symbol if we have already checked the file.
|
||||
if checked.contains(&name) {
|
||||
continue;
|
||||
};
|
||||
|
||||
// Find the imported program.
|
||||
let program = import_parser
|
||||
.get_import(&name)
|
||||
.ok_or_else(|| SymbolTableError::unknown_package(&name, &symbol.span))?;
|
||||
|
||||
// Check the imported program.
|
||||
self.check_duplicate_program(program, import_parser)?;
|
||||
|
||||
// Push the imported file's name to checked import files.
|
||||
checked.push(name);
|
||||
|
||||
// Store the imported symbol.
|
||||
// self.insert_import_symbol(symbol, program)?; // TODO (collinc97) uncomment this line when public/private import scopes are implemented.
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// Inserts core package name and type information into the symbol table.
|
||||
@ -220,7 +322,7 @@ impl SymbolTable {
|
||||
// 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()));
|
||||
self.insert_circuit_name(name, ParameterType::from(circuit.clone()))?;
|
||||
|
||||
// Create new circuit type for symbol.
|
||||
let circuit_type = CircuitType::new(&self, circuit)?;
|
||||
@ -232,6 +334,41 @@ impl SymbolTable {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// Checks that a given import statement contains imported names that 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_import(
|
||||
&mut self,
|
||||
import: &ImportStatement,
|
||||
import_parser: &ImportParser,
|
||||
) -> Result<(), SymbolTableError> {
|
||||
// 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.
|
||||
if let Some(package) = core_package {
|
||||
return self.insert_core_package(package);
|
||||
}
|
||||
|
||||
// // Get the import file name from the import statement.
|
||||
// let import_file_name = import.get_file_name();
|
||||
//
|
||||
// // Check if the import file name exists in the import parser.
|
||||
// let program = import_parser
|
||||
// .get_import(&import_file_name)
|
||||
// .ok_or_else(|| SymbolTableError::unknown_package(import_file_name, &import.span))?;
|
||||
//
|
||||
// // Check the imported file.
|
||||
// self.check_duplicate_program(program, import_parser)?;
|
||||
|
||||
// Attempt to insert the imported names into the symbol table.
|
||||
self.insert_import(import, import_parser)
|
||||
}
|
||||
|
||||
///
|
||||
/// Checks that all given imported names exist in the list of imported programs.
|
||||
///
|
||||
@ -240,31 +377,40 @@ impl SymbolTable {
|
||||
///
|
||||
pub fn check_imports(
|
||||
&mut self,
|
||||
imports: &Vec<Import>,
|
||||
imports: &Vec<ImportStatement>,
|
||||
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")
|
||||
}
|
||||
}
|
||||
self.check_import(import, import_parser)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// Checks for duplicate import, circuit, and function names given a 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 check_duplicate_program(
|
||||
&mut self,
|
||||
program: &Program,
|
||||
import_parser: &ImportParser,
|
||||
) -> Result<(), SymbolTableError> {
|
||||
// Check unresolved program import names.
|
||||
self.check_imports(&program.imports, import_parser)?;
|
||||
|
||||
// Check unresolved program circuit names.
|
||||
self.check_duplicate_circuits(&program.circuits)?;
|
||||
|
||||
// Check unresolved program function names.
|
||||
self.check_duplicate_functions(&program.functions)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// Checks for duplicate circuit names given a hashmap of circuits.
|
||||
///
|
||||
@ -278,15 +424,7 @@ impl SymbolTable {
|
||||
// Iterate over circuit names and definitions.
|
||||
for (identifier, circuit) in circuits.iter() {
|
||||
// Attempt to insert the circuit name into the symbol table.
|
||||
let duplicate = self.insert_name(identifier.to_string(), ParameterType::from(circuit.clone()));
|
||||
|
||||
// Check that the circuit name is unique.
|
||||
if duplicate.is_some() {
|
||||
return Err(SymbolTableError::duplicate_circuit(
|
||||
identifier.clone(),
|
||||
circuit.circuit_name.span.clone(),
|
||||
));
|
||||
}
|
||||
self.insert_circuit_name(identifier.to_string(), ParameterType::from(circuit.clone()))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -305,15 +443,7 @@ impl SymbolTable {
|
||||
// Iterate over function names and definitions.
|
||||
for (identifier, function) in functions.iter() {
|
||||
// Attempt to insert the function name into the symbol table.
|
||||
let duplicate = self.insert_name(identifier.to_string(), ParameterType::from(function.clone()));
|
||||
|
||||
// Check that the function name is unique.
|
||||
if duplicate.is_some() {
|
||||
return Err(SymbolTableError::duplicate_function(
|
||||
identifier.clone(),
|
||||
function.identifier.span.clone(),
|
||||
));
|
||||
}
|
||||
self.insert_function_name(identifier.to_string(), ParameterType::from(function.clone()))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -59,7 +59,7 @@ impl TestStaticCheck {
|
||||
let program = self.typed.into_repr();
|
||||
|
||||
// Create new symbol table.
|
||||
let _symbol_table = StaticCheck::run(&program).unwrap();
|
||||
let _symbol_table = StaticCheck::run_with_input(&program).unwrap();
|
||||
}
|
||||
|
||||
///
|
||||
|
@ -14,7 +14,7 @@
|
||||
// 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::{Circuit, Function, FunctionInput, Identifier, Import, TestFunction};
|
||||
use crate::{Circuit, Function, FunctionInput, Identifier, ImportStatement, TestFunction};
|
||||
use leo_ast::{
|
||||
annotations::{Annotation, AnnotationArguments, AnnotationName},
|
||||
definitions::{AnnotatedDefinition, Definition},
|
||||
@ -24,7 +24,7 @@ use std::collections::HashMap;
|
||||
|
||||
pub fn load_annotation(
|
||||
annotated_definition: AnnotatedDefinition,
|
||||
_imports: &mut Vec<Import>,
|
||||
_imports: &mut Vec<ImportStatement>,
|
||||
_circuits: &mut HashMap<Identifier, Circuit>,
|
||||
_functions: &mut HashMap<Identifier, Function>,
|
||||
tests: &mut HashMap<Identifier, TestFunction>,
|
||||
|
@ -14,42 +14,50 @@
|
||||
// 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/>.
|
||||
|
||||
//! The import type for a Leo program.
|
||||
|
||||
use crate::{Package, Span};
|
||||
use leo_ast::imports::Import as AstImport;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
/// Represents an import statement in a Leo program.
|
||||
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Import {
|
||||
pub struct ImportStatement {
|
||||
pub package: Package,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl<'ast> From<AstImport<'ast>> for Import {
|
||||
impl ImportStatement {
|
||||
///
|
||||
/// Returns the the package file name of the self import statement.
|
||||
///
|
||||
pub fn get_file_name(&self) -> &str {
|
||||
&self.package.name.name
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> From<AstImport<'ast>> for ImportStatement {
|
||||
fn from(import: AstImport<'ast>) -> Self {
|
||||
Import {
|
||||
ImportStatement {
|
||||
package: Package::from(import.package),
|
||||
span: Span::from(import.span),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Import {
|
||||
impl ImportStatement {
|
||||
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "import {};", self.package)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Import {
|
||||
impl fmt::Display for ImportStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.format(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Import {
|
||||
impl fmt::Debug for ImportStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.format(f)
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
//! A typed Leo program consists of import, circuit, and function definitions.
|
||||
//! Each defined type consists of typed statements and expressions.
|
||||
|
||||
use crate::{load_annotation, Circuit, Function, FunctionInput, Identifier, Import, TestFunction};
|
||||
use crate::{load_annotation, Circuit, Function, FunctionInput, Identifier, ImportStatement, TestFunction};
|
||||
use leo_ast::{definitions::Definition, files::File};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -28,7 +28,7 @@ use std::collections::HashMap;
|
||||
pub struct Program {
|
||||
pub name: String,
|
||||
pub expected_input: Vec<FunctionInput>,
|
||||
pub imports: Vec<Import>,
|
||||
pub imports: Vec<ImportStatement>,
|
||||
pub circuits: HashMap<Identifier, Circuit>,
|
||||
pub functions: HashMap<Identifier, Function>,
|
||||
pub tests: HashMap<Identifier, TestFunction>,
|
||||
@ -50,7 +50,7 @@ impl<'ast> Program {
|
||||
.to_owned()
|
||||
.into_iter()
|
||||
.for_each(|definition| match definition {
|
||||
Definition::Import(import) => imports.push(Import::from(import)),
|
||||
Definition::Import(import) => imports.push(ImportStatement::from(import)),
|
||||
Definition::Circuit(circuit) => {
|
||||
circuits.insert(Identifier::from(circuit.identifier.clone()), Circuit::from(circuit));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user