summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/parse/mod.rs48
-rw-r--r--src/parse/parser.rs10
-rw-r--r--src/parse/tokens.rs2
-rw-r--r--src/pretty.rs6
-rw-r--r--src/syntax/expr.rs4
-rw-r--r--src/syntax/token.rs6
-rw-r--r--tests/ref/code/import.pngbin4148 -> 4279 bytes
-rw-r--r--tests/typ/code/block-scoping.typ2
-rw-r--r--tests/typ/code/import.typ131
-rw-r--r--tests/typ/code/importable/cycle1.typ4
-rw-r--r--tests/typ/code/importable/cycle2.typ4
-rw-r--r--tools/support/typst.tmLanguage.json4
12 files changed, 113 insertions, 108 deletions
diff --git a/src/parse/mod.rs b/src/parse/mod.rs
index 1d893ad9..c3d532a7 100644
--- a/src/parse/mod.rs
+++ b/src/parse/mod.rs
@@ -728,33 +728,29 @@ fn import_expr(p: &mut Parser) -> Option<Expr> {
let start = p.next_start();
p.assert(Token::Import);
- let mut import_expr = None;
- if let Some(path) = expr(p) {
- let imports = if p.expect(Token::Using) {
- if p.eat_if(Token::Star) {
- // This is the wildcard scenario.
- Imports::Wildcard
- } else {
- // This is the list of identifier scenario.
- p.start_group(Group::Expr, TokenMode::Code);
- let items = collection(p).0;
- if items.is_empty() {
- p.expected_at("import items", p.prev_end());
- }
-
- let idents = idents(p, items);
- p.end_group();
- Imports::Idents(idents)
- }
- } else {
- Imports::Idents(vec![])
- };
+ let imports = if p.eat_if(Token::Star) {
+ // This is the wildcard scenario.
+ Imports::Wildcard
+ } else {
+ // This is the list of identifiers scenario.
+ p.start_group(Group::Imports, TokenMode::Code);
+ let items = collection(p).0;
+ if items.is_empty() {
+ p.expected_at("import items", p.prev_end());
+ }
+ p.end_group();
+ Imports::Idents(idents(p, items))
+ };
- import_expr = Some(Expr::Import(ImportExpr {
- span: p.span(start),
- imports,
- path: Box::new(path),
- }));
+ let mut import_expr = None;
+ if p.expect(Token::From) {
+ if let Some(path) = expr(p) {
+ import_expr = Some(Expr::Import(ImportExpr {
+ span: p.span(start),
+ imports,
+ path: Box::new(path),
+ }));
+ }
}
import_expr
diff --git a/src/parse/parser.rs b/src/parse/parser.rs
index 8ea80d68..1e0f2f5d 100644
--- a/src/parse/parser.rs
+++ b/src/parse/parser.rs
@@ -51,6 +51,8 @@ pub enum Group {
Stmt,
/// A group for a single expression, ended by a line break.
Expr,
+ /// A group for import items, ended by a semicolon, line break or `from`.
+ Imports,
}
impl<'s> Parser<'s> {
@@ -128,6 +130,7 @@ impl<'s> Parser<'s> {
Group::Brace => self.assert(Token::LeftBrace),
Group::Stmt => {}
Group::Expr => {}
+ Group::Imports => {}
}
}
@@ -149,6 +152,7 @@ impl<'s> Parser<'s> {
Group::Brace => Some((Token::RightBrace, true)),
Group::Stmt => Some((Token::Semicolon, false)),
Group::Expr => None,
+ Group::Imports => None,
} {
if self.next == Some(end) {
// Bump the delimeter and return. No need to rescan in this case.
@@ -361,6 +365,7 @@ impl<'s> Parser<'s> {
Token::RightBracket => self.inside(Group::Bracket),
Token::RightBrace => self.inside(Group::Brace),
Token::Semicolon => self.inside(Group::Stmt),
+ Token::From => self.inside(Group::Imports),
Token::Space(n) => n >= 1 && self.stop_at_newline(),
_ => false,
} {
@@ -371,7 +376,10 @@ impl<'s> Parser<'s> {
/// Whether the active group ends at a newline.
fn stop_at_newline(&self) -> bool {
let active = self.groups.last().map(|group| group.kind);
- matches!(active, Some(Group::Stmt) | Some(Group::Expr))
+ matches!(
+ active,
+ Some(Group::Stmt) | Some(Group::Expr) | Some(Group::Imports)
+ )
}
/// Whether we are inside the given group.
diff --git a/src/parse/tokens.rs b/src/parse/tokens.rs
index aebe7b70..d979d005 100644
--- a/src/parse/tokens.rs
+++ b/src/parse/tokens.rs
@@ -496,7 +496,7 @@ fn keyword(id: &str) -> Option<Token<'static>> {
"return" => Token::Return,
"import" => Token::Import,
"include" => Token::Include,
- "using" => Token::Using,
+ "from" => Token::From,
_ => return None,
})
}
diff --git a/src/pretty.rs b/src/pretty.rs
index ff8841f3..46b82eb7 100644
--- a/src/pretty.rs
+++ b/src/pretty.rs
@@ -440,9 +440,9 @@ impl Pretty for ForPattern {
impl Pretty for ImportExpr {
fn pretty(&self, p: &mut Printer) {
p.push_str("import ");
- self.path.pretty(p);
- p.push_str(" using ");
self.imports.pretty(p);
+ p.push_str(" from ");
+ self.path.pretty(p);
}
}
@@ -737,7 +737,7 @@ mod tests {
roundtrip("#while x {y}");
roundtrip("#for x in y {z}");
roundtrip("#for k, x in y {z}");
- roundtrip("#import \"file.typ\" using *");
+ roundtrip("#import * from \"file.typ\"");
roundtrip("#include \"chapter1.typ\"");
}
diff --git a/src/syntax/expr.rs b/src/syntax/expr.rs
index f5b79122..c4462ff8 100644
--- a/src/syntax/expr.rs
+++ b/src/syntax/expr.rs
@@ -59,7 +59,7 @@ pub enum Expr {
While(WhileExpr),
/// A for loop expression: `for x in y { z }`.
For(ForExpr),
- /// An import expression: `import "utils.typ" using a, b, c`.
+ /// An import expression: `import a, b, c from "utils.typ"`.
Import(ImportExpr),
/// An include expression: `include "chapter1.typ"`.
Include(IncludeExpr),
@@ -466,7 +466,7 @@ pub struct LetExpr {
pub init: Option<Box<Expr>>,
}
-/// An import expression: `import "utils.typ" using a, b, c`.
+/// An import expression: `import a, b, c from "utils.typ"`.
#[derive(Debug, Clone, PartialEq)]
pub struct ImportExpr {
/// The source code location.
diff --git a/src/syntax/token.rs b/src/syntax/token.rs
index 425dac10..c14cf9f7 100644
--- a/src/syntax/token.rs
+++ b/src/syntax/token.rs
@@ -101,8 +101,8 @@ pub enum Token<'s> {
Import,
/// The `include` keyword.
Include,
- /// The `using` keyword.
- Using,
+ /// The `from` keyword.
+ From,
/// One or more whitespace characters.
///
/// The contained `usize` denotes the number of newlines that were contained
@@ -254,7 +254,7 @@ impl<'s> Token<'s> {
Self::Return => "keyword `return`",
Self::Import => "keyword `import`",
Self::Include => "keyword `include`",
- Self::Using => "keyword `using`",
+ Self::From => "keyword `from`",
Self::Space(_) => "space",
Self::Text(_) => "text",
Self::UnicodeEscape(_) => "unicode escape sequence",
diff --git a/tests/ref/code/import.png b/tests/ref/code/import.png
index 0a811495..75d4adce 100644
--- a/tests/ref/code/import.png
+++ b/tests/ref/code/import.png
Binary files differ
diff --git a/tests/typ/code/block-scoping.typ b/tests/typ/code/block-scoping.typ
index ed689f3d..7970ee1b 100644
--- a/tests/typ/code/block-scoping.typ
+++ b/tests/typ/code/block-scoping.typ
@@ -21,7 +21,7 @@
---
// Double block creates a scope.
{{
- import "target.typ" using b
+ import b from "target.typ"
test(b, 1)
}}
diff --git a/tests/typ/code/import.typ b/tests/typ/code/import.typ
index 30dc556c..18ebd499 100644
--- a/tests/typ/code/import.typ
+++ b/tests/typ/code/import.typ
@@ -4,21 +4,21 @@
// Test importing semantics.
// A named import.
-#import "target.typ" using item
+#import item from "target.typ"
#test(item(1, 2), 3)
// Test that this will be overwritten.
#let value = [foo]
// Import multiple things.
-// Error: 28-29 expected expression, found comma
-#import "target.typ" using ,fn, value
+// Error: 9-10 expected expression, found comma
+#import ,fn, value from "target.typ"
#fn[Like and Subscribe!]
#value
// Code mode
{
- import "target.typ" using b
+ import b from "target.typ"
test(b, 1)
}
@@ -29,91 +29,92 @@
#d
// A wildcard import.
-#import "target.typ" using *
+#import * from "target.typ"
// It exists now!
#d
+// Who needs whitespace anyways?
+#import*from"target.typ"
+
+// Should output `Hi`.
+// Stop at semicolon.
+#import a, c from "target.typ";bye
+
+// Allow the trailing comma.
+#import a, c, from "target.typ"
+
---
// Test bad imports.
// Ref: false
-// Error: 9-11 file not found
-#import "" using name
-
-// Error: 9-20 file not found
-#import "lib/0.2.1" using *
+// Error: 19-21 file not found
+#import name from ""
-// Error: 9-20 file not found
-#import "lib@0.2.1" using *
+// Error: 16-27 file not found
+#import * from "lib/0.2.1"
// Some non-text stuff.
-// Error: 9-30 file is not valid utf-8
-#import "../../res/rhino.png" using *
+// Error: 16-37 file is not valid utf-8
+#import * from "../../res/rhino.png"
// Unresolved import.
-// Error: 28-40 unresolved import
-#import "target.typ" using non_existing
+// Error: 9-21 unresolved import
+#import non_existing from "target.typ"
// Cyclic import.
-// Error: 9-34 cyclic import
-#import "./importable/cycle1.typ" using *
+// Error: 16-41 cyclic import
+#import * from "./importable/cycle1.typ"
---
-// Test syntax.
-
-// Missing file.
-// Error: 9-10 expected expression, found star
-#import *
-
-// Should output `"target.typ"`.
-// Error: 1-7 unexpected keyword `using`
-#using "target.typ"
+// Test bad syntax.
-// Should output `target`.
-// Error: 3:9-4:8 file not found
-// Error: 3:8 expected semicolon or line break
-// Error: 2:8 expected keyword `using`
-#import "target.typ
-using "target
+// Error: 2:8 expected import items
+// Error: 1:8 expected keyword `from`
+#import
-// Should output `@ 0.2.1 using`.
-// Error: 2:21 expected semicolon or line break
-// Error: 1:21 expected keyword `using`
-#import "target.typ" @ 0.2.1 using *
+// Error: 2:9-2:19 expected identifier
+// Error: 1:19 expected keyword `from`
+#import "file.typ"
-// Error: 3:21 expected keyword `using`
-// Error: 2:21 expected semicolon or line break
-// Error: 1:22-1:28 unexpected keyword `using`
-#import "target.typ" #using *
+// Error: 2:16-2:19 expected identifier
+// Error: 1:22 expected keyword `from`
+#import afrom, "b", c
-// Error: 2:21 expected semicolon or line break
-// Error: 1:21 expected keyword `using`
-#import "target.typ" usinga,b,c
+// Error: 8 expected import items
+#import from "target.typ"
-// Error: 27 expected import items
-#import "target.typ" using
+// Error: 2:9-2:10 expected expression, found assignment operator
+// Error: 1:10 expected import items
+#import = from "target.typ"
-// Error: 2:28-2:29 expected expression, found assignment operator
-// Error: 1:29 expected import items
-#import "target.typ" using =
-
-// Allow the trailing comma.
-#import "target.typ" using a, c,
+// Error: 15 expected expression
+#import * from
// An additional trailing comma.
-// Error: 36-37 expected expression, found comma
-#import "target.typ" using a, b, c,,
-
-// Star in the list.
-// Error: 2:31-2:32 expected expression, found star
-// Error: 32-33 expected expression, found comma
-#import "target.typ" using a, *, b
+// Error: 17-18 expected expression, found comma
+#import a, b, c,, from "target.typ"
-// Stop at semicolon.
-#import "target.typ" using a, c;Hi
+// Should output `"target.typ"`.
+// Error: 1-6 unexpected keyword `from`
+#from "target.typ"
-// Who needs whitespace anyways?
-#import "target.typ"using *
-#import"target.typ"using*
-#import "target.typ"using *
+// Should output `target`.
+// Error: 2:16-3:2 file not found
+// Error: 2:2 expected semicolon or line break
+#import * from "target.typ
+"target
+
+// Should output `@ 0.2.1`.
+// Error: 28 expected semicolon or line break
+#import * from "target.typ" @ 0.2.1
+
+// A star in the list.
+// Error: 2:12-2:13 expected expression, found star
+// Error: 1:13-1:14 expected expression, found comma
+#import a, *, b from "target.typ"
+
+// An item after a star.
+// Should output `, a from "target.typ"`.
+// Error: 10 expected keyword `from`
+#import *, a from "target.typ"
diff --git a/tests/typ/code/importable/cycle1.typ b/tests/typ/code/importable/cycle1.typ
index e251686d..ae755fa0 100644
--- a/tests/typ/code/importable/cycle1.typ
+++ b/tests/typ/code/importable/cycle1.typ
@@ -1,7 +1,7 @@
// Ref: false
-// Error: 9-21 cyclic import
-#import "cycle2.typ" using *
+// Error: 16-28 cyclic import
+#import * from "cycle2.typ"
#let inaccessible = "wow"
This is the first element of an import cycle.
diff --git a/tests/typ/code/importable/cycle2.typ b/tests/typ/code/importable/cycle2.typ
index 8071ec6b..d4f94564 100644
--- a/tests/typ/code/importable/cycle2.typ
+++ b/tests/typ/code/importable/cycle2.typ
@@ -1,7 +1,7 @@
// Ref: false
-// Error: 9-21 cyclic import
-#import "cycle1.typ" using *
+// Error: 16-28 cyclic import
+#import * from "cycle1.typ"
#let val = "much cycle"
This is the second element of an import cycle.
diff --git a/tools/support/typst.tmLanguage.json b/tools/support/typst.tmLanguage.json
index 33e4c3db..6c767b31 100644
--- a/tools/support/typst.tmLanguage.json
+++ b/tools/support/typst.tmLanguage.json
@@ -119,7 +119,7 @@
},
{
"name": "keyword.other.typst",
- "match": "(#)(as|in|with|from|using)\\b",
+ "match": "(#)(as|in|with|from)\\b",
"captures": { "1": { "name": "punctuation.definition.keyword.typst" } }
},
{
@@ -231,7 +231,7 @@
},
{
"name": "keyword.other.typst",
- "match": "\\b(pub|let|as|in|with|import|include|from|using)\\b"
+ "match": "\\b(pub|let|as|in|with|import|include|from)\\b"
},
{ "include": "#constants" },
{