summaryrefslogtreecommitdiff
path: root/crates/typst-syntax
diff options
context:
space:
mode:
authorPg Biel <9021226+PgBiel@users.noreply.github.com>2023-08-30 08:36:02 -0300
committerGitHub <noreply@github.com>2023-08-30 13:36:02 +0200
commit19b91d59d1467956f8175146a16b63d303eee0d7 (patch)
treee2099ccec6fd1fa260597cb9700cbff43e747199 /crates/typst-syntax
parent8a0dd88f1073f8fac9b2db022027eae3752dffd7 (diff)
Allow renaming imports with `as` (#1923)
Diffstat (limited to 'crates/typst-syntax')
-rw-r--r--crates/typst-syntax/src/ast.rs71
-rw-r--r--crates/typst-syntax/src/kind.rs3
-rw-r--r--crates/typst-syntax/src/parser.rs14
3 files changed, 85 insertions, 3 deletions
diff --git a/crates/typst-syntax/src/ast.rs b/crates/typst-syntax/src/ast.rs
index 7cf0cbd5..fd3bfebe 100644
--- a/crates/typst-syntax/src/ast.rs
+++ b/crates/typst-syntax/src/ast.rs
@@ -1988,6 +1988,15 @@ impl<'a> ModuleImport<'a> {
_ => Option::None,
})
}
+
+ /// The name this module was assigned to, if it was renamed with `as`
+ /// (`renamed` in `import "..." as renamed`).
+ pub fn new_name(self) -> Option<Ident<'a>> {
+ self.0
+ .children()
+ .skip_while(|child| child.kind() != SyntaxKind::As)
+ .find_map(SyntaxNode::cast)
+ }
}
/// The items that ought to be imported from a file.
@@ -2005,9 +2014,65 @@ node! {
}
impl<'a> ImportItems<'a> {
- /// The items to import from the module.
- pub fn idents(self) -> impl DoubleEndedIterator<Item = Ident<'a>> {
- self.0.children().filter_map(SyntaxNode::cast)
+ /// Returns an iterator over the items to import from the module.
+ pub fn iter(self) -> impl DoubleEndedIterator<Item = ImportItem<'a>> {
+ self.0.children().filter_map(|child| match child.kind() {
+ SyntaxKind::RenamedImportItem => child.cast().map(ImportItem::Renamed),
+ SyntaxKind::Ident => child.cast().map(ImportItem::Simple),
+ _ => Option::None,
+ })
+ }
+}
+
+/// An imported item, potentially renamed to another identifier.
+#[derive(Debug, Copy, Clone, Hash)]
+pub enum ImportItem<'a> {
+ /// A non-renamed import (the item's name in the scope is the same as its
+ /// name).
+ Simple(Ident<'a>),
+ /// A renamed import (the item was bound to a different name in the scope
+ /// than the one it was defined as).
+ Renamed(RenamedImportItem<'a>),
+}
+
+impl<'a> ImportItem<'a> {
+ /// The original name of the imported item, at its source. This will be the
+ /// equal to the bound name if the item wasn't renamed with 'as'.
+ pub fn original_name(self) -> Ident<'a> {
+ match self {
+ Self::Simple(name) => name,
+ Self::Renamed(renamed_item) => renamed_item.original_name(),
+ }
+ }
+
+ /// The name which this import item was bound to. Corresponds to the new
+ /// name, if it was renamed; otherwise, it's just its original name.
+ pub fn bound_name(self) -> Ident<'a> {
+ match self {
+ Self::Simple(name) => name,
+ Self::Renamed(renamed_item) => renamed_item.new_name(),
+ }
+ }
+}
+
+node! {
+ /// A renamed import item: `a as d`
+ RenamedImportItem
+}
+
+impl<'a> RenamedImportItem<'a> {
+ /// The original name of the imported item (`a` in `a as d`).
+ pub fn original_name(self) -> Ident<'a> {
+ self.0.cast_first_match().unwrap_or_default()
+ }
+
+ /// The new name of the imported item (`d` in `a as d`).
+ pub fn new_name(self) -> Ident<'a> {
+ self.0
+ .children()
+ .filter_map(SyntaxNode::cast)
+ .nth(1)
+ .unwrap_or_default()
}
}
diff --git a/crates/typst-syntax/src/kind.rs b/crates/typst-syntax/src/kind.rs
index 49119720..669ca0f2 100644
--- a/crates/typst-syntax/src/kind.rs
+++ b/crates/typst-syntax/src/kind.rs
@@ -242,6 +242,8 @@ pub enum SyntaxKind {
ModuleImport,
/// Items to import from a module: `a, b, c`.
ImportItems,
+ /// A renamed import item: `a as d`.
+ RenamedImportItem,
/// A module include: `include "chapter1.typ"`.
ModuleInclude,
/// A break from a loop: `break`.
@@ -465,6 +467,7 @@ impl SyntaxKind {
Self::ForLoop => "for-loop expression",
Self::ModuleImport => "`import` expression",
Self::ImportItems => "import items",
+ Self::RenamedImportItem => "renamed import item",
Self::ModuleInclude => "`include` expression",
Self::LoopBreak => "`break` expression",
Self::LoopContinue => "`continue` expression",
diff --git a/crates/typst-syntax/src/parser.rs b/crates/typst-syntax/src/parser.rs
index e0476ec8..306ac798 100644
--- a/crates/typst-syntax/src/parser.rs
+++ b/crates/typst-syntax/src/parser.rs
@@ -1138,6 +1138,12 @@ fn module_import(p: &mut Parser) {
let m = p.marker();
p.assert(SyntaxKind::Import);
code_expr(p);
+ if p.eat_if(SyntaxKind::As) {
+ // Allow renaming a full module import.
+ // If items are included, both the full module and the items are
+ // imported at the same time.
+ p.expect(SyntaxKind::Ident);
+ }
if p.eat_if(SyntaxKind::Colon) && !p.eat_if(SyntaxKind::Star) {
import_items(p);
}
@@ -1147,9 +1153,17 @@ fn module_import(p: &mut Parser) {
fn import_items(p: &mut Parser) {
let m = p.marker();
while !p.eof() && !p.at(SyntaxKind::Semicolon) {
+ let item_marker = p.marker();
if !p.eat_if(SyntaxKind::Ident) {
p.unexpected();
}
+
+ // Rename imported item.
+ if p.eat_if(SyntaxKind::As) {
+ p.expect(SyntaxKind::Ident);
+ p.wrap(item_marker, SyntaxKind::RenamedImportItem);
+ }
+
if p.current().is_terminator() {
break;
}