diff --git a/ast/src/imports/import.rs b/ast/src/imports/import.rs
deleted file mode 100644
index a3819e8621..0000000000
--- a/ast/src/imports/import.rs
+++ /dev/null
@@ -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 .
-
-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)
- }
-}
diff --git a/ast/src/imports/import_symbol.rs b/ast/src/imports/import_symbol.rs
deleted file mode 100644
index c0b4de7443..0000000000
--- a/ast/src/imports/import_symbol.rs
+++ /dev/null
@@ -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 .
-
-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,
- /// 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
- }
-}
diff --git a/ast/src/imports/mod.rs b/ast/src/imports/mod.rs
index 29f787db60..0abc99f168 100644
--- a/ast/src/imports/mod.rs
+++ b/ast/src/imports/mod.rs
@@ -14,20 +14,106 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see .
-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,
+ /// 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,
+ },
+ /// A nested import of items or sub-packages.
+ Nested {
+ /// The sub-tree specifying what to import from the `base`.
+ tree: Vec,
+ },
+}
diff --git a/ast/src/imports/package.rs b/ast/src/imports/package.rs
deleted file mode 100644
index ce693f604d..0000000000
--- a/ast/src/imports/package.rs
+++ /dev/null
@@ -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 .
-
-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)
- }
-}
diff --git a/ast/src/imports/package_access.rs b/ast/src/imports/package_access.rs
deleted file mode 100644
index 28745f6921..0000000000
--- a/ast/src/imports/package_access.rs
+++ /dev/null
@@ -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 .
-
-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),
- /// 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)
- }
-}
diff --git a/ast/src/imports/package_or_packages.rs b/ast/src/imports/package_or_packages.rs
deleted file mode 100644
index 780f99f1e5..0000000000
--- a/ast/src/imports/package_or_packages.rs
+++ /dev/null
@@ -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 .
-
-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,
- }
- }
-}
diff --git a/ast/src/imports/packages.rs b/ast/src/imports/packages.rs
deleted file mode 100644
index dafe4cae9d..0000000000
--- a/ast/src/imports/packages.rs
+++ /dev/null
@@ -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 .
-
-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,
- /// 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)
- }
-}
diff --git a/ast/src/reducer/reconstructing_director.rs b/ast/src/reducer/reconstructing_director.rs
index 963a8e84e2..ba70f7d729 100644
--- a/ast/src/reducer/reconstructing_director.rs
+++ b/ast/src/reducer/reconstructing_director.rs
@@ -496,27 +496,33 @@ impl ReconstructingDirector {
self.reducer.reduce_function_input(input, new)
}
- pub fn reduce_package_or_packages(&mut self, package_or_packages: &PackageOrPackages) -> Result {
- 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 {
+ let new = ImportTree {
+ base: tree
+ .base
+ .iter()
+ .map(|i| self.reduce_identifier(i))
+ .collect::>()?,
+
+ 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::>()?,
+ },
+ },
+ 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 {
- 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, Program)> {
diff --git a/ast/src/reducer/reconstructing_reducer.rs b/ast/src/reducer/reconstructing_reducer.rs
index 4118ce6f8d..808f4ecd35 100644
--- a/ast/src/reducer/reconstructing_reducer.rs
+++ b/ast/src/reducer/reconstructing_reducer.rs
@@ -421,21 +421,13 @@ pub trait ReconstructingReducer {
Ok(new)
}
- fn reduce_package_or_packages(
- &mut self,
- _package_or_packages: &PackageOrPackages,
- new: PackageOrPackages,
- ) -> Result {
+ fn reduce_import_tree(&mut self, _tree: &ImportTree, new: ImportTree) -> Result {
Ok(new)
}
- fn reduce_import_statement(
- &mut self,
- import: &ImportStatement,
- package_or_packages: PackageOrPackages,
- ) -> Result {
+ fn reduce_import_statement(&mut self, import: &ImportStatement, tree: ImportTree) -> Result {
Ok(ImportStatement {
- package_or_packages,
+ tree,
span: import.span.clone(),
})
}
diff --git a/parser/src/parser/context.rs b/parser/src/parser/context.rs
index b338216cd1..4c7479311d 100644
--- a/parser/src/parser/context.rs
+++ b/parser/src/parser/context.rs
@@ -425,6 +425,8 @@ impl<'a> ParserContext<'a> {
trailing = false;
break;
}
+
+ trailing = true;
}
// Parse closing delimiter.
diff --git a/parser/src/parser/file.rs b/parser/src/parser/file.rs
index 52f8a4489c..3d6e473b2f 100644
--- a/parser/src/parser/file.rs
+++ b/parser/src/parser/file.rs
@@ -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, 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 {
- 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 {
// 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 {
- 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 {
+ // 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 {
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,
})
}