diff --git a/compiler/src/compiler.rs b/compiler/src/compiler.rs index c2d2a90ef9..2cc1ca660b 100644 --- a/compiler/src/compiler.rs +++ b/compiler/src/compiler.rs @@ -165,7 +165,7 @@ impl> Compiler { 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)?; diff --git a/compiler/src/import/store/import.rs b/compiler/src/import/store/import.rs index d25175d877..a332e54cd7 100644 --- a/compiler/src/import/store/import.rs +++ b/compiler/src/import/store/import.rs @@ -14,9 +14,10 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -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> ConstrainedProgram { pub(crate) fn store_import( &mut self, scope: String, - import: &Import, + import: &ImportStatement, imported_programs: &ImportParser, ) -> Result<(), ImportError> { // Fetch core packages diff --git a/compiler/src/import/store/imported_symbols.rs b/compiler/src/import/store/imported_symbols.rs index 80545e01f4..c9196c4310 100644 --- a/compiler/src/import/store/imported_symbols.rs +++ b/compiler/src/import/store/imported_symbols.rs @@ -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 . - -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 . +// +// 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)), +// } +// } +// } diff --git a/compiler/src/import/store/mod.rs b/compiler/src/import/store/mod.rs index 7633655956..fee7b3a914 100644 --- a/compiler/src/import/store/mod.rs +++ b/compiler/src/import/store/mod.rs @@ -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::*; diff --git a/dynamic-check/tests/mod.rs b/dynamic-check/tests/mod.rs index ffac91f162..63441b4496 100644 --- a/dynamic-check/tests/mod.rs +++ b/dynamic-check/tests/mod.rs @@ -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(); diff --git a/imports/src/parser/import_parser.rs b/imports/src/parser/import_parser.rs index c8e3b41eae..66322776dc 100644 --- a/imports/src/parser/import_parser.rs +++ b/imports/src/parser/import_parser.rs @@ -15,7 +15,7 @@ // along with the Leo library. If not, see . 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) } diff --git a/imports/src/parser/parse_symbol.rs b/imports/src/parser/parse_symbol.rs index c5638d00ef..811cf7b087 100644 --- a/imports/src/parser/parse_symbol.rs +++ b/imports/src/parser/parse_symbol.rs @@ -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(()) } diff --git a/static-check/src/errors/symbol_table.rs b/static-check/src/errors/symbol_table.rs index 36505648a5..bae3ed451c 100644 --- a/static-check/src/errors/symbol_table.rs +++ b/static-check/src/errors/symbol_table.rs @@ -14,9 +14,9 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -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()) } } diff --git a/static-check/src/imports/imported_symbols.rs b/static-check/src/imports/imported_symbols.rs new file mode 100644 index 0000000000..8ee3c747c3 --- /dev/null +++ b/static-check/src/imports/imported_symbols.rs @@ -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 . + +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)), + } + } +} diff --git a/static-check/src/imports/mod.rs b/static-check/src/imports/mod.rs new file mode 100644 index 0000000000..000a0a4885 --- /dev/null +++ b/static-check/src/imports/mod.rs @@ -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 . + +pub mod imported_symbols; +pub use self::imported_symbols::*; diff --git a/static-check/src/lib.rs b/static-check/src/lib.rs index b985aab375..22815db239 100644 --- a/static-check/src/lib.rs +++ b/static-check/src/lib.rs @@ -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::*; diff --git a/static-check/src/static_check.rs b/static-check/src/static_check.rs index b9144edb05..4775c94900 100644 --- a/static-check/src/static_check.rs +++ b/static-check/src/static_check.rs @@ -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 { + 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 { 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)) } /// diff --git a/static-check/src/symbol_table.rs b/static-check/src/symbol_table.rs index 985339de95..75c87da921 100644 --- a/static-check/src/symbol_table.rs +++ b/static-check/src/symbol_table.rs @@ -14,10 +14,10 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -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 { + 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, + imports: &Vec, 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(()) diff --git a/static-check/tests/mod.rs b/static-check/tests/mod.rs index b748415e6b..155b8665ae 100644 --- a/static-check/tests/mod.rs +++ b/static-check/tests/mod.rs @@ -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(); } /// diff --git a/typed/src/annotation.rs b/typed/src/annotation.rs index 6ffa0fad8c..67439869b2 100644 --- a/typed/src/annotation.rs +++ b/typed/src/annotation.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -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, + _imports: &mut Vec, _circuits: &mut HashMap, _functions: &mut HashMap, tests: &mut HashMap, diff --git a/typed/src/imports/import.rs b/typed/src/imports/import.rs index aeac7f0d3b..3c47d204ab 100644 --- a/typed/src/imports/import.rs +++ b/typed/src/imports/import.rs @@ -14,42 +14,50 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -//! 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> 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> 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) } diff --git a/typed/src/program.rs b/typed/src/program.rs index 90cfb41fc4..6dd3339ea6 100644 --- a/typed/src/program.rs +++ b/typed/src/program.rs @@ -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, - pub imports: Vec, + pub imports: Vec, pub circuits: HashMap, pub functions: HashMap, pub tests: HashMap, @@ -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)); }