Skip to content

Commit 73b4604

Browse files
committed
Allow new import syntax
- Replace wildcard import `_` with `*`, which is what basically all other languages use - Replace renaming `=>` with a soft keyword `as`. - Allow `as` outside braces, as in ```scala import scala.collection.mutable as mut import NumPy as np ```
1 parent 4ae35b9 commit 73b4604

File tree

4 files changed

+91
-81
lines changed

4 files changed

+91
-81
lines changed

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 69 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -3066,8 +3066,8 @@ object Parsers {
30663066

30673067
type ImportConstr = (Tree, List[ImportSelector]) => Tree
30683068

3069-
/** Import ::= `import' [`given'] [ImportExpr {`,' ImportExpr}
3070-
* Export ::= `export' [`given'] [ImportExpr {`,' ImportExpr}
3069+
/** Import ::= `import' ImportExpr {‘,’ ImportExpr}
3070+
* Export ::= `export' ImportExpr {‘,’ ImportExpr}
30713071
*/
30723072
def importClause(leading: Token, mkTree: ImportConstr): List[Tree] = {
30733073
val offset = accept(leading)
@@ -3101,48 +3101,49 @@ object Parsers {
31013101
ctx.compilationUnit.sourceVersion = Some(SourceVersion.valueOf(imported.toString))
31023102
Import(tree, selectors)
31033103

3104-
/** ImportExpr ::= SimpleRef {‘.’ id} ‘.’ ImportSpec
3105-
* ImportSpec ::= id
3106-
* | ‘_’
3107-
* | ‘given’
3108-
* | ‘{’ ImportSelectors) ‘}’
3109-
*/
3110-
def importExpr(mkTree: ImportConstr): () => Tree = {
3111-
3112-
/** '_' */
3113-
def wildcardSelectorId() = atSpan(in.skipToken()) { Ident(nme.WILDCARD) }
3114-
def givenSelectorId(start: Offset) = atSpan(start) { Ident(nme.EMPTY) }
3104+
/** ImportExpr ::= SimpleRef {‘.’ id} ‘.’ ImportSpec
3105+
* | SimpleRef ‘as’ id
3106+
* ImportSpec ::= NamedSelector
3107+
* | WildcardSelector
3108+
* | ‘{’ ImportSelectors) ‘}’
3109+
* ImportSelectors ::= NamedSelector [‘,’ ImportSelectors]
3110+
* | WildCardSelector {‘,’ WildCardSelector}
3111+
* NamedSelector ::= id [‘as’ (id | ‘_’)]
3112+
* WildCardSelector ::= ‘*' | ‘given’ [InfixType]
3113+
*/
3114+
def importExpr(mkTree: ImportConstr): () => Tree =
3115+
3116+
/** ‘*' | ‘_' */
3117+
def wildcardSelector() =
3118+
ImportSelector(atSpan(in.skipToken()) { Ident(nme.WILDCARD) })
3119+
3120+
/** 'given [InfixType]' */
3121+
def givenSelector() =
3122+
ImportSelector(
3123+
atSpan(in.skipToken()) { Ident(nme.EMPTY )},
3124+
bound =
3125+
if canStartTypeTokens.contains(in.token) then rejectWildcardType(infixType())
3126+
else EmptyTree)
3127+
3128+
/** id [‘as’ (id | ‘_’) */
3129+
def namedSelector(from: Ident) =
3130+
if in.token == ARROW || isIdent(nme.as) then
3131+
atSpan(startOffset(from), in.skipToken()) {
3132+
val to = if in.token == USCORE then wildcardIdent() else termIdent()
3133+
ImportSelector(from, if to.name == nme.ERROR then EmptyTree else to)
3134+
}
3135+
else ImportSelector(from)
31153136

3116-
/** ImportSelectors ::= id [‘=>’ id | ‘=>’ ‘_’] [‘,’ ImportSelectors]
3117-
* | WildCardSelector {‘,’ WildCardSelector}
3118-
* WildCardSelector ::= ‘given’ [InfixType]
3119-
* | ‘_'
3120-
*/
31213137
def importSelectors(idOK: Boolean): List[ImportSelector] =
3122-
val isWildcard = in.token == USCORE || in.token == GIVEN
3138+
val isWildcard = in.token == USCORE || in.token == GIVEN || isIdent(nme.raw.STAR)
31233139
val selector = atSpan(in.offset) {
31243140
in.token match
3125-
case USCORE =>
3126-
ImportSelector(wildcardSelectorId())
3127-
case GIVEN =>
3128-
val start = in.skipToken()
3129-
if in.token == USCORE then
3130-
deprecationWarning(em"`given _` is deprecated in imports; replace with just `given`", start)
3131-
in.nextToken()
3132-
ImportSelector(givenSelectorId(start)) // Let the selector span all of `given`; needed for -Ytest-pickler
3133-
else if canStartTypeTokens.contains(in.token) then
3134-
ImportSelector(givenSelectorId(start), bound = rejectWildcardType(infixType()))
3135-
else
3136-
ImportSelector(givenSelectorId(start))
3141+
case USCORE => wildcardSelector()
3142+
case GIVEN => givenSelector()
31373143
case _ =>
3138-
val from = termIdent()
31393144
if !idOK then syntaxError(i"named imports cannot follow wildcard imports")
3140-
if in.token == ARROW then
3141-
atSpan(startOffset(from), in.skipToken()) {
3142-
val to = if in.token == USCORE then wildcardIdent() else termIdent()
3143-
ImportSelector(from, if to.name == nme.ERROR then EmptyTree else to)
3144-
}
3145-
else ImportSelector(from)
3145+
if isIdent(nme.raw.STAR) then wildcardSelector()
3146+
else namedSelector(termIdent())
31463147
}
31473148
val rest =
31483149
if in.token == COMMA then
@@ -3153,26 +3154,36 @@ object Parsers {
31533154
selector :: rest
31543155

31553156
def importSelection(qual: Tree): Tree =
3156-
accept(DOT)
3157-
in.token match
3158-
case USCORE =>
3159-
mkTree(qual, ImportSelector(wildcardSelectorId()) :: Nil)
3160-
case GIVEN =>
3161-
mkTree(qual, ImportSelector(givenSelectorId(in.skipToken())) :: Nil)
3162-
case LBRACE =>
3163-
mkTree(qual, inBraces(importSelectors(idOK = true)))
3164-
case _ =>
3165-
val start = in.offset
3166-
val name = ident()
3167-
if in.token == DOT then
3168-
importSelection(atSpan(startOffset(qual), start) { Select(qual, name) })
3169-
else
3170-
atSpan(startOffset(qual)) {
3171-
mkTree(qual, ImportSelector(atSpan(start) { Ident(name) }) :: Nil)
3172-
}
3173-
3174-
() => importSelection(simpleRef())
3175-
}
3157+
if in.isIdent(nme.as) && qual.isInstanceOf[RefTree] then
3158+
qual match
3159+
case Select(qual1, name) =>
3160+
val from = Ident(name).withSpan(Span(qual.span.point, qual.span.end, 0))
3161+
mkTree(qual1, namedSelector(from) :: Nil)
3162+
case qual: Ident =>
3163+
mkTree(EmptyTree, namedSelector(qual) :: Nil)
3164+
else
3165+
accept(DOT)
3166+
in.token match
3167+
case USCORE =>
3168+
mkTree(qual, wildcardSelector() :: Nil)
3169+
case GIVEN =>
3170+
mkTree(qual, givenSelector() :: Nil)
3171+
case LBRACE =>
3172+
mkTree(qual, inBraces(importSelectors(idOK = true)))
3173+
case _ =>
3174+
if isIdent(nme.raw.STAR) then
3175+
mkTree(qual, wildcardSelector() :: Nil)
3176+
else
3177+
val start = in.offset
3178+
val name = ident()
3179+
if in.token == DOT then
3180+
importSelection(atSpan(startOffset(qual), start) { Select(qual, name) })
3181+
else
3182+
mkTree(qual, namedSelector(atSpan(start) { Ident(name) }) :: Nil)
3183+
end importSelection
3184+
3185+
() => atSpan(in.offset) { importSelection(simpleRef()) }
3186+
end importExpr
31763187

31773188
/** Def ::= val PatDef
31783189
* | var VarDef

docs/docs/internals/syntax.md

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ type val var while with yield
120120
### Soft keywords
121121
122122
```
123-
derives end extension infix inline opaque open transparent using | * + -
123+
as derives end extension infix inline opaque open transparent using | * + -
124124
```
125125
126126
See the [separate section on soft keywords](./soft-modifier.md) for additional
@@ -258,8 +258,7 @@ ArgumentExprs ::= ParArgumentExprs
258258
BlockExpr ::= <<< (CaseClauses | Block) >>>
259259
Block ::= {BlockStat semi} [BlockResult] Block(stats, expr?)
260260
BlockStat ::= Import
261-
| {Annotation {nl}} [‘implicit’ | ‘lazy’] Def
262-
| {Annotation {nl}} {LocalModifier} TmplDef
261+
| {Annotation {nl}} {LocalModifier} Def
263262
| Extension
264263
| Expr1
265264
| EndMarker
@@ -353,16 +352,16 @@ AccessQualifier ::= ‘[’ id ‘]’
353352
Annotation ::= ‘@’ SimpleType1 {ParArgumentExprs} Apply(tpe, args)
354353
355354
Import ::= ‘import’ ImportExpr {‘,’ ImportExpr}
355+
Export ::= ‘export’ ImportExpr {‘,’ ImportExpr}
356356
ImportExpr ::= SimpleRef {‘.’ id} ‘.’ ImportSpec Import(expr, sels)
357-
ImportSpec ::= id
358-
| ‘_’
359-
| ‘given’
357+
| SimpleRef ‘as’ id Import(EmptyTree, ImportSelector(ref, id))
358+
ImportSpec ::= NamedSelector
359+
| WildcardSelector
360360
| ‘{’ ImportSelectors) ‘}’
361-
ImportSelectors ::= id [‘=>’ id | ‘=>’ ‘_’] [‘,’ ImportSelectors]
361+
NamedSelector ::= id [‘as’ (id | ‘_’)]
362+
WildCardSelector ::= ‘*' | ‘given’ [InfixType]
363+
ImportSelectors ::= NamedSelector [‘,’ ImportSelectors]
362364
| WildCardSelector {‘,’ WildCardSelector}
363-
WildCardSelector ::= ‘given’ [InfixType]
364-
| ‘_'
365-
Export ::= ‘export’ ImportExpr {‘,’ ImportExpr}
366365
367366
EndMarker ::= ‘end’ EndMarkerTag -- when followed by EOL
368367
EndMarkerTag ::= id | ‘if’ | ‘while’ | ‘for’ | ‘match’ | ‘try’

docs/docs/reference/soft-modifier.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@ Otherwise, soft keywords are treated specially in the following situations:
1717
- `end`, if it appears at the start of a line following a statement (i.e. definition or toplevel expression)
1818
- `extension`, if it appears at the start of a statement and is followed by `(` or `[`.
1919
- `using`, if it appears at the start of a parameter or argument list.
20+
- `as`, in a renaming import clause
2021
- `|`, if it separates two patterns in an alternative.
2122
- `+`, `-`, if they appear in front of a type parameter.
22-
- `*`, if it follows the type of a parameter or if it appears in
23-
a vararg type ascription `x: _*`.
23+
- `*`, in a wildcard import, or it follows the type of a parameter, or if it appears in
24+
a vararg splice `x*`.
2425

2526
Everywhere else a soft keyword is treated as a normal identifier.

docs/docs/reference/syntax.md

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ type val var while with yield
119119
### Soft keywords
120120

121121
```
122-
derives end extension infix inline opaque open transparent using | * + -
122+
as derives end extension infix inline opaque open transparent using | * + -
123123
```
124124

125125
See the [separate section on soft keywords](./soft-modifier.md) for additional
@@ -222,7 +222,7 @@ Expr1 ::= [‘inline’] ‘if’ ‘(’ Expr ‘)’ {nl} Expr [[
222222
Ascription ::= ‘:’ InfixType
223223
| ‘:’ Annotation {Annotation}
224224
Catches ::= ‘catch’ (Expr | ExprCaseClause)
225-
PostfixExpr ::= InfixExpr [id]
225+
PostfixExpr ::= InfixExpr [id] -- only if language.postfixOperators is enabled
226226
InfixExpr ::= PrefixExpr
227227
| InfixExpr id [nl] InfixExpr
228228
| InfixExpr MatchClause
@@ -254,8 +254,7 @@ ArgumentExprs ::= ParArgumentExprs
254254
BlockExpr ::= <<< (CaseClauses | Block) >>>
255255
Block ::= {BlockStat semi} [BlockResult]
256256
BlockStat ::= Import
257-
| {Annotation {nl}} [‘implicit’ | ‘lazy’] Def
258-
| {Annotation {nl}} {LocalModifier} TmplDef
257+
| {Annotation {nl}} {LocalModifier} Def
259258
| Extension
260259
| Expr1
261260
| EndMarker
@@ -344,16 +343,16 @@ AccessQualifier ::= ‘[’ id ‘]’
344343
Annotation ::= ‘@’ SimpleType1 {ParArgumentExprs}
345344
346345
Import ::= ‘import’ ImportExpr {‘,’ ImportExpr}
346+
Export ::= ‘export’ ImportExpr {‘,’ ImportExpr}
347347
ImportExpr ::= SimpleRef {‘.’ id} ‘.’ ImportSpec
348-
ImportSpec ::= id
349-
| ‘_’
350-
| ‘given’
348+
| SimpleRef ‘as’ id
349+
ImportSpec ::= NamedSelector
350+
| WildcardSelector
351351
| ‘{’ ImportSelectors) ‘}’
352-
ImportSelectors ::= id [‘=>’ id | ‘=>’ ‘_’] [‘,’ ImportSelectors]
352+
NamedSelector ::= id [‘as’ (id | ‘_’)]
353+
WildCardSelector ::= ‘*' | ‘given’ [InfixType]
354+
ImportSelectors ::= NamedSelector [‘,’ ImportSelectors]
353355
| WildCardSelector {‘,’ WildCardSelector}
354-
WildCardSelector ::= ‘given’ [InfixType]
355-
| ‘_'
356-
Export ::= ‘export’ ImportExpr {‘,’ ImportExpr}
357356
358357
EndMarker ::= ‘end’ EndMarkerTag -- when followed by EOL
359358
EndMarkerTag ::= id | ‘if’ | ‘while’ | ‘for’ | ‘match’ | ‘try’

0 commit comments

Comments
 (0)