Skip to content

Commit 977b622

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 f6ccc8c commit 977b622

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)
@@ -3097,48 +3097,49 @@ object Parsers {
30973097
ctx.compilationUnit.sourceVersion = Some(SourceVersion.valueOf(imported.toString))
30983098
Import(tree, selectors)
30993099

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

3112-
/** ImportSelectors ::= id [‘=>’ id | ‘=>’ ‘_’] [‘,’ ImportSelectors]
3113-
* | WildCardSelector {‘,’ WildCardSelector}
3114-
* WildCardSelector ::= ‘given’ [InfixType]
3115-
* | ‘_'
3116-
*/
31173133
def importSelectors(idOK: Boolean): List[ImportSelector] =
3118-
val isWildcard = in.token == USCORE || in.token == GIVEN
3134+
val isWildcard = in.token == USCORE || in.token == GIVEN || isIdent(nme.raw.STAR)
31193135
val selector = atSpan(in.offset) {
31203136
in.token match
3121-
case USCORE =>
3122-
ImportSelector(wildcardSelectorId())
3123-
case GIVEN =>
3124-
val start = in.skipToken()
3125-
if in.token == USCORE then
3126-
deprecationWarning(em"`given _` is deprecated in imports; replace with just `given`", start)
3127-
in.nextToken()
3128-
ImportSelector(givenSelectorId(start)) // Let the selector span all of `given`; needed for -Ytest-pickler
3129-
else if canStartTypeTokens.contains(in.token) then
3130-
ImportSelector(givenSelectorId(start), bound = rejectWildcardType(infixType()))
3131-
else
3132-
ImportSelector(givenSelectorId(start))
3137+
case USCORE => wildcardSelector()
3138+
case GIVEN => givenSelector()
31333139
case _ =>
3134-
val from = termIdent()
31353140
if !idOK then syntaxError(i"named imports cannot follow wildcard imports")
3136-
if in.token == ARROW then
3137-
atSpan(startOffset(from), in.skipToken()) {
3138-
val to = if in.token == USCORE then wildcardIdent() else termIdent()
3139-
ImportSelector(from, if to.name == nme.ERROR then EmptyTree else to)
3140-
}
3141-
else ImportSelector(from)
3141+
if isIdent(nme.raw.STAR) then wildcardSelector()
3142+
else namedSelector(termIdent())
31423143
}
31433144
val rest =
31443145
if in.token == COMMA then
@@ -3149,26 +3150,36 @@ object Parsers {
31493150
selector :: rest
31503151

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

31733184
/** Def ::= val PatDef
31743185
* | 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)