mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-12-01 08:19:32 +03:00
Merge pull request #1591 from AleoHQ/import-tree
[WIP] Refactor / Simplify imports in the AST
This commit is contained in:
commit
9febc01c19
@ -1,58 +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 crate::PackageOrPackages;
|
||||
use leo_span::{Span, Symbol};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
/// Represents an import statement in a Leo program.
|
||||
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ImportStatement {
|
||||
/// The package or packages to import.
|
||||
pub package_or_packages: PackageOrPackages,
|
||||
/// The span, excluding the `;`.
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl ImportStatement {
|
||||
/// Returns the the package file name of the self import statement.
|
||||
pub fn get_file_name(&self) -> Symbol {
|
||||
match self.package_or_packages {
|
||||
PackageOrPackages::Package(ref package) => package.name.name,
|
||||
PackageOrPackages::Packages(ref packages) => packages.name.name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ImportStatement {
|
||||
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "import {};", self.package_or_packages)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ImportStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.format(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ImportStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.format(f)
|
||||
}
|
||||
}
|
@ -1,76 +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 crate::Identifier;
|
||||
|
||||
use leo_span::{sym, Span};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
/// An import of `symbol` possibly renamed to `alias`,
|
||||
/// e.g., `symbol` or `symbol as alias`.
|
||||
///
|
||||
/// This is the leaf of an import tree.
|
||||
#[derive(Clone, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ImportSymbol {
|
||||
pub symbol: Identifier,
|
||||
/// The name, if any, to import `symbol` as.
|
||||
/// If not specified, `symbol` is the name it is imported under.
|
||||
pub alias: Option<Identifier>,
|
||||
/// The span including `symbol` and possibly `as alias`.
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl fmt::Display for ImportSymbol {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if self.alias.is_some() {
|
||||
write!(f, "{} as {}", self.symbol, self.alias.as_ref().unwrap())
|
||||
} else {
|
||||
write!(f, "{}", self.symbol)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO (collin): remove this
|
||||
impl fmt::Debug for ImportSymbol {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if self.alias.is_some() {
|
||||
write!(f, "{} as {}", self.symbol, self.alias.as_ref().unwrap())
|
||||
} else {
|
||||
write!(f, "{}", self.symbol)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ImportSymbol {
|
||||
/// Creates a glob `*` import.
|
||||
pub fn star(span: &Span) -> Self {
|
||||
Self {
|
||||
symbol: Identifier {
|
||||
name: sym::Star,
|
||||
span: span.clone(),
|
||||
},
|
||||
alias: None,
|
||||
span: span.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Is this a glob import?
|
||||
pub fn is_star(&self) -> bool {
|
||||
self.symbol.name == sym::Star
|
||||
}
|
||||
}
|
@ -14,20 +14,106 @@
|
||||
// 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 import;
|
||||
pub use import::*;
|
||||
use crate::Identifier;
|
||||
use leo_span::{Span, Symbol};
|
||||
|
||||
pub mod import_symbol;
|
||||
pub use import_symbol::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
pub mod package;
|
||||
pub use package::*;
|
||||
/// Represents an import statement in a Leo program.
|
||||
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ImportStatement {
|
||||
/// The tree specifying what items or packages to import.
|
||||
pub tree: ImportTree,
|
||||
/// The span, excluding the `;`.
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
pub mod packages;
|
||||
pub use packages::*;
|
||||
impl ImportStatement {
|
||||
/// Returns the the package file name of the self import statement.
|
||||
pub fn get_file_name(&self) -> Symbol {
|
||||
self.tree.base.first().unwrap().name
|
||||
}
|
||||
}
|
||||
|
||||
pub mod package_or_packages;
|
||||
pub use package_or_packages::*;
|
||||
impl fmt::Display for ImportStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "import {};", self.tree)
|
||||
}
|
||||
}
|
||||
|
||||
pub mod package_access;
|
||||
pub use package_access::*;
|
||||
impl fmt::Debug for ImportStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
/// An import tree specifies item(s) to import.
|
||||
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ImportTree {
|
||||
/// A path to the base item or package to import or import from.
|
||||
/// The list is always non-empty.
|
||||
pub base: Vec<Identifier>,
|
||||
/// Specifies the kind of import and the meaning of `base`.
|
||||
/// This includes plain imports, renames, globs (`*`), and nested imports.
|
||||
pub kind: ImportTreeKind,
|
||||
/// The span for the import excluding `import` and `;`.
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl fmt::Display for ImportTree {
|
||||
/// Formats `self` to `f`.
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
// Format the path.
|
||||
for (i, part) in self.base.iter().enumerate() {
|
||||
write!(f, "{}", part)?;
|
||||
if i < self.base.len() - 1 {
|
||||
write!(f, ".")?;
|
||||
}
|
||||
}
|
||||
|
||||
// Format the kind.
|
||||
match &self.kind {
|
||||
ImportTreeKind::Glob { .. } => write!(f, ".*"),
|
||||
ImportTreeKind::Leaf { alias: None } => Ok(()),
|
||||
ImportTreeKind::Leaf { alias: Some(alias) } => write!(f, "as {}", alias),
|
||||
ImportTreeKind::Nested { tree } => {
|
||||
write!(f, ".(")?;
|
||||
for (i, node) in tree.iter().enumerate() {
|
||||
write!(f, "{}", node)?;
|
||||
if i < tree.len() - 1 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
}
|
||||
write!(f, ")")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ImportTree {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
/// Specifies the import kind and the meaning of `base`.
|
||||
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ImportTreeKind {
|
||||
/// A glob import `*`.
|
||||
Glob {
|
||||
/// The span for the `*`.
|
||||
span: Span,
|
||||
},
|
||||
/// A leaf package to import.
|
||||
Leaf {
|
||||
/// When specified, the package is imported under a different name.
|
||||
/// Otherwise, the `base` name is used as in the `ImportTree`.
|
||||
alias: Option<Identifier>,
|
||||
},
|
||||
/// A nested import of items or sub-packages.
|
||||
Nested {
|
||||
/// The sub-tree specifying what to import from the `base`.
|
||||
tree: Vec<ImportTree>,
|
||||
},
|
||||
}
|
||||
|
@ -1,51 +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 crate::{common::Identifier, PackageAccess};
|
||||
use leo_span::Span;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
/// A package import specification.
|
||||
#[derive(Clone, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Package {
|
||||
/// The base package to import `access` from.
|
||||
pub name: Identifier,
|
||||
/// A specification of what to import from `name`.
|
||||
pub access: PackageAccess,
|
||||
/// The span including the `name` and the `access`.
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl Package {
|
||||
/// Formats `self` to `f`.
|
||||
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}.{}", self.name, self.access)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Package {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.format(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Package {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.format(f)
|
||||
}
|
||||
}
|
@ -1,92 +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 crate::{ImportSymbol, Node, Package, Packages};
|
||||
use leo_span::Span;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub enum PackageAccess {
|
||||
/// A glob import `*`.
|
||||
Star {
|
||||
/// The span for the `*`.
|
||||
span: Span,
|
||||
},
|
||||
/// A subpackage to import.
|
||||
SubPackage(Box<Package>),
|
||||
/// A leaf package to import.
|
||||
Symbol(ImportSymbol),
|
||||
/// Several subpackages to import.
|
||||
// FIXME(Centril): This structure seems convoluted and unclear.
|
||||
// Refactor and simplify the types to:
|
||||
// https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/struct.UseTree.html.
|
||||
Multiple(Packages),
|
||||
}
|
||||
|
||||
impl Node for PackageAccess {
|
||||
fn span(&self) -> &Span {
|
||||
match self {
|
||||
PackageAccess::Star { span } => span,
|
||||
PackageAccess::SubPackage(package) => &package.span,
|
||||
PackageAccess::Symbol(package) => &package.span,
|
||||
PackageAccess::Multiple(package) => &package.span,
|
||||
}
|
||||
}
|
||||
|
||||
fn set_span(&mut self, span: Span) {
|
||||
match self {
|
||||
PackageAccess::Star { span } => *span = span.clone(),
|
||||
PackageAccess::SubPackage(package) => package.span = span,
|
||||
PackageAccess::Symbol(package) => package.span = span,
|
||||
PackageAccess::Multiple(package) => package.span = span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PackageAccess {
|
||||
/// Formats `self` to `f`.
|
||||
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
PackageAccess::Star { .. } => write!(f, "*"),
|
||||
PackageAccess::SubPackage(ref package) => write!(f, "{}", package),
|
||||
PackageAccess::Symbol(ref symbol) => write!(f, "{}", symbol),
|
||||
PackageAccess::Multiple(ref packages) => {
|
||||
write!(f, "(")?;
|
||||
for (i, access) in packages.accesses.iter().enumerate() {
|
||||
write!(f, "{}", access)?;
|
||||
if i < packages.accesses.len() - 1 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
}
|
||||
write!(f, ")")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for PackageAccess {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.format(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for PackageAccess {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.format(f)
|
||||
}
|
||||
}
|
@ -1,77 +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 crate::{Node, Package, Packages};
|
||||
use leo_span::Span;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
/// A specification of what packages to import.
|
||||
#[derive(Clone, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub enum PackageOrPackages {
|
||||
/// Instruction to import a single package or item.
|
||||
Package(Package),
|
||||
/// Instruction to import a packages or items with a common prefix.
|
||||
Packages(Packages),
|
||||
}
|
||||
|
||||
impl PackageOrPackages {
|
||||
/// Formats `self` to `f`.
|
||||
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
PackageOrPackages::Package(ref package) => write!(f, "{}", package),
|
||||
PackageOrPackages::Packages(ref packages) => {
|
||||
write!(f, "(")?;
|
||||
for (i, access) in packages.accesses.iter().enumerate() {
|
||||
write!(f, "{}", access)?;
|
||||
if i < packages.accesses.len() - 1 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
}
|
||||
write!(f, ")")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for PackageOrPackages {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.format(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for PackageOrPackages {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.format(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Node for PackageOrPackages {
|
||||
fn span(&self) -> &Span {
|
||||
match self {
|
||||
PackageOrPackages::Package(package) => &package.span,
|
||||
PackageOrPackages::Packages(packages) => &packages.span,
|
||||
}
|
||||
}
|
||||
|
||||
fn set_span(&mut self, span: Span) {
|
||||
match self {
|
||||
PackageOrPackages::Package(package) => package.span = span,
|
||||
PackageOrPackages::Packages(packages) => packages.span = span,
|
||||
}
|
||||
}
|
||||
}
|
@ -1,58 +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 crate::{common::Identifier, PackageAccess};
|
||||
use leo_span::Span;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
/// Import of `name.(accesses)`, that is, several sub-packages or items within `name`.
|
||||
#[derive(Clone, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Packages {
|
||||
/// The common package that `accesses` are contained within.
|
||||
pub name: Identifier,
|
||||
/// The packages or items to import within the package `name`.
|
||||
pub accesses: Vec<PackageAccess>,
|
||||
/// The entire span for `name.(accesses)`.
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl Packages {
|
||||
/// Formats `self` to `f`.
|
||||
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}.(", self.name)?;
|
||||
for (i, access) in self.accesses.iter().enumerate() {
|
||||
write!(f, "{}", access)?;
|
||||
if i < self.accesses.len() - 1 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
}
|
||||
write!(f, ")")
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Packages {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.format(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Packages {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.format(f)
|
||||
}
|
||||
}
|
@ -496,27 +496,33 @@ impl<R: ReconstructingReducer> ReconstructingDirector<R> {
|
||||
self.reducer.reduce_function_input(input, new)
|
||||
}
|
||||
|
||||
pub fn reduce_package_or_packages(&mut self, package_or_packages: &PackageOrPackages) -> Result<PackageOrPackages> {
|
||||
let new = match package_or_packages {
|
||||
PackageOrPackages::Package(package) => PackageOrPackages::Package(Package {
|
||||
name: self.reduce_identifier(&package.name)?,
|
||||
access: package.access.clone(),
|
||||
span: package.span.clone(),
|
||||
}),
|
||||
PackageOrPackages::Packages(packages) => PackageOrPackages::Packages(Packages {
|
||||
name: self.reduce_identifier(&packages.name)?,
|
||||
accesses: packages.accesses.clone(),
|
||||
span: packages.span.clone(),
|
||||
}),
|
||||
pub fn reduce_import_tree(&mut self, tree: &ImportTree) -> Result<ImportTree> {
|
||||
let new = ImportTree {
|
||||
base: tree
|
||||
.base
|
||||
.iter()
|
||||
.map(|i| self.reduce_identifier(i))
|
||||
.collect::<Result<_>>()?,
|
||||
|
||||
kind: match &tree.kind {
|
||||
ImportTreeKind::Glob { .. } | ImportTreeKind::Leaf { alias: None } => tree.kind.clone(),
|
||||
ImportTreeKind::Leaf { alias: Some(alias) } => {
|
||||
let alias = self.reduce_identifier(alias)?;
|
||||
ImportTreeKind::Leaf { alias: Some(alias) }
|
||||
}
|
||||
ImportTreeKind::Nested { tree } => ImportTreeKind::Nested {
|
||||
tree: tree.iter().map(|n| self.reduce_import_tree(n)).collect::<Result<_>>()?,
|
||||
},
|
||||
},
|
||||
span: tree.span.clone(),
|
||||
};
|
||||
|
||||
self.reducer.reduce_package_or_packages(package_or_packages, new)
|
||||
self.reducer.reduce_import_tree(tree, new)
|
||||
}
|
||||
|
||||
pub fn reduce_import_statement(&mut self, import: &ImportStatement) -> Result<ImportStatement> {
|
||||
let package_or_packages = self.reduce_package_or_packages(&import.package_or_packages)?;
|
||||
|
||||
self.reducer.reduce_import_statement(import, package_or_packages)
|
||||
let tree = self.reduce_import_tree(&import.tree)?;
|
||||
self.reducer.reduce_import_statement(import, tree)
|
||||
}
|
||||
|
||||
pub fn reduce_import(&mut self, identifier: &[Symbol], import: &Program) -> Result<(Vec<Symbol>, Program)> {
|
||||
|
@ -421,21 +421,13 @@ pub trait ReconstructingReducer {
|
||||
Ok(new)
|
||||
}
|
||||
|
||||
fn reduce_package_or_packages(
|
||||
&mut self,
|
||||
_package_or_packages: &PackageOrPackages,
|
||||
new: PackageOrPackages,
|
||||
) -> Result<PackageOrPackages> {
|
||||
fn reduce_import_tree(&mut self, _tree: &ImportTree, new: ImportTree) -> Result<ImportTree> {
|
||||
Ok(new)
|
||||
}
|
||||
|
||||
fn reduce_import_statement(
|
||||
&mut self,
|
||||
import: &ImportStatement,
|
||||
package_or_packages: PackageOrPackages,
|
||||
) -> Result<ImportStatement> {
|
||||
fn reduce_import_statement(&mut self, import: &ImportStatement, tree: ImportTree) -> Result<ImportStatement> {
|
||||
Ok(ImportStatement {
|
||||
package_or_packages,
|
||||
tree,
|
||||
span: import.span.clone(),
|
||||
})
|
||||
}
|
||||
|
@ -425,6 +425,8 @@ impl<'a> ParserContext<'a> {
|
||||
trailing = false;
|
||||
break;
|
||||
}
|
||||
|
||||
trailing = true;
|
||||
}
|
||||
|
||||
// Parse closing delimiter.
|
||||
|
@ -18,7 +18,7 @@ use super::*;
|
||||
use crate::KEYWORD_TOKENS;
|
||||
|
||||
use leo_errors::{ParserError, Result};
|
||||
use leo_span::{sym, Span};
|
||||
use leo_span::sym;
|
||||
|
||||
impl ParserContext<'_> {
|
||||
///
|
||||
@ -146,64 +146,6 @@ impl ParserContext<'_> {
|
||||
Ok(name)
|
||||
}
|
||||
|
||||
/// Returns a vector of [`PackageAccess`] AST nodes if the next tokens represent package access
|
||||
/// expressions within an import statement.
|
||||
pub fn parse_package_accesses(&mut self, start: &Span) -> Result<(Vec<PackageAccess>, Span)> {
|
||||
let (out, _, end) = self.parse_paren_comma_list(|p| p.parse_package_access().map(Some))?;
|
||||
|
||||
if out.is_empty() {
|
||||
self.emit_err(ParserError::invalid_import_list(&end));
|
||||
}
|
||||
|
||||
Ok((out, start + &end))
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns a [`PackageAccess`] AST node if the next tokens represent a package access expression
|
||||
/// within an import statement.
|
||||
///
|
||||
pub fn parse_package_access(&mut self) -> Result<PackageAccess> {
|
||||
if let Some(SpannedToken { span, .. }) = self.eat(Token::Mul) {
|
||||
Ok(PackageAccess::Star { span })
|
||||
} else {
|
||||
let mut name = self.expect_ident()?;
|
||||
|
||||
// Allow dashes in the accessed members (should only be used for directories).
|
||||
// If imported member does not exist, code will fail on ASG level.
|
||||
if let Token::Minus = self.peek_token().as_ref() {
|
||||
let span = self.expect(Token::Minus)?;
|
||||
name.span = name.span + span;
|
||||
let next = self.expect_ident()?;
|
||||
name.span = name.span + next.span;
|
||||
name.name = Symbol::intern(&format!("{}-{}", name.name, next.name));
|
||||
}
|
||||
|
||||
if self.peek_token().as_ref() == &Token::Dot {
|
||||
self.backtrack(SpannedToken {
|
||||
token: Token::Ident(name.name),
|
||||
span: name.span,
|
||||
});
|
||||
Ok(match self.parse_package_path()? {
|
||||
PackageOrPackages::Package(p) => PackageAccess::SubPackage(Box::new(p)),
|
||||
PackageOrPackages::Packages(p) => PackageAccess::Multiple(p),
|
||||
})
|
||||
} else if self.eat(Token::As).is_some() {
|
||||
let alias = self.expect_ident()?;
|
||||
Ok(PackageAccess::Symbol(ImportSymbol {
|
||||
span: &name.span + &alias.span,
|
||||
symbol: name,
|
||||
alias: Some(alias),
|
||||
}))
|
||||
} else {
|
||||
Ok(PackageAccess::Symbol(ImportSymbol {
|
||||
span: name.span.clone(),
|
||||
symbol: name,
|
||||
alias: None,
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an [`Identifier`] AST node if the next tokens represent a valid package name.
|
||||
pub fn parse_package_name(&mut self) -> Result<Identifier> {
|
||||
// Build the package name, starting with valid characters up to a dash `-` (Token::Minus).
|
||||
@ -257,33 +199,57 @@ impl ParserContext<'_> {
|
||||
Ok(base)
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns a [`PackageOrPackages`] AST node if the next tokens represent a valid package import
|
||||
/// Returns an [`ImportTree`] AST node if the next tokens represent a valid package import
|
||||
/// with accesses.
|
||||
///
|
||||
pub fn parse_package_path(&mut self) -> Result<PackageOrPackages> {
|
||||
let name = self.parse_package_name()?;
|
||||
self.expect(Token::Dot)?;
|
||||
if self.peek_is_left_par() {
|
||||
let (accesses, span) = self.parse_package_accesses(&name.span)?;
|
||||
Ok(PackageOrPackages::Packages(Packages { span, name, accesses }))
|
||||
} else {
|
||||
let access = self.parse_package_access()?;
|
||||
let span = &name.span + access.span();
|
||||
Ok(PackageOrPackages::Package(Package { span, name, access }))
|
||||
fn parse_import_tree(&mut self) -> Result<ImportTree> {
|
||||
// Parse the first part of the path.
|
||||
let first_name = self.parse_package_name()?;
|
||||
let start = first_name.span.clone();
|
||||
let mut base = vec![first_name];
|
||||
|
||||
let make = |base, end, kind| {
|
||||
let span = start + end;
|
||||
ImportTree { base, span, kind }
|
||||
};
|
||||
|
||||
// Paths are separated by `.`s.
|
||||
while self.eat(Token::Dot).is_some() {
|
||||
if self.peek_is_left_par() {
|
||||
// Encountered `.(`, so we have a nested import. Recurse!
|
||||
let (tree, _, end) = self.parse_paren_comma_list(|p| p.parse_import_tree().map(Some))?;
|
||||
|
||||
if tree.is_empty() {
|
||||
self.emit_err(ParserError::invalid_import_list(&end));
|
||||
}
|
||||
|
||||
return Ok(make(base, end, ImportTreeKind::Nested { tree }));
|
||||
} else if let Some(SpannedToken { span, .. }) = self.eat(Token::Mul) {
|
||||
// Encountered `.*`, so we have a glob import.
|
||||
return Ok(make(base, span.clone(), ImportTreeKind::Glob { span }));
|
||||
}
|
||||
|
||||
// Parse another path segment.
|
||||
base.push(self.parse_package_name()?);
|
||||
}
|
||||
|
||||
let (end, alias) = if self.eat(Token::As).is_some() {
|
||||
// Encountered `as`, so interpret as `path as rename`.
|
||||
let alias = self.expect_ident()?;
|
||||
(alias.span.clone(), Some(alias))
|
||||
} else {
|
||||
(base.last().unwrap().span.clone(), None)
|
||||
};
|
||||
Ok(make(base, end, ImportTreeKind::Leaf { alias }))
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns a [`ImportStatement`] AST node if the next tokens represent an import statement.
|
||||
///
|
||||
pub fn parse_import_statement(&mut self) -> Result<ImportStatement> {
|
||||
self.expect(Token::Import)?;
|
||||
let package_or_packages = self.parse_package_path()?;
|
||||
let tree = self.parse_import_tree()?;
|
||||
self.expect(Token::Semicolon)?;
|
||||
Ok(ImportStatement {
|
||||
span: package_or_packages.span().clone(),
|
||||
package_or_packages,
|
||||
span: tree.span.clone(),
|
||||
tree,
|
||||
})
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user