Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update syntax.md #19670

Merged
merged 5 commits into from
Feb 14, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 86 additions & 88 deletions compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1532,13 +1532,15 @@ object Parsers {
* PolyFunType ::= HKTypeParamClause '=>' Type
* | HKTypeParamClause ‘->’ [CaptureSet] Type -- under pureFunctions
* FunTypeArgs ::= InfixType
* | `(' [ [ ‘['erased'] FunArgType {`,' FunArgType } ] `)'
* | '(' [ ‘['erased'] TypedFunParam {',' TypedFunParam } ')'
* | `(' [ FunArgType {`,' FunArgType } ] `)'
* | '(' [ TypedFunParam {',' TypedFunParam } ')'
* MatchType ::= InfixType `match` <<< TypeCaseClauses >>>
*/
def typ(): Tree =
val start = in.offset
var imods = Modifiers()
var erasedArgs: ListBuffer[Boolean] = ListBuffer()
odersky marked this conversation as resolved.
Show resolved Hide resolved

def functionRest(params: List[Tree]): Tree =
val paramSpan = Span(start, in.lastOffset)
atSpan(start, in.offset) {
Expand Down Expand Up @@ -1567,7 +1569,8 @@ object Parsers {
else
accept(ARROW)

val resultType = if isPure then capturesAndResult(typ) else typ()
val resultType =
if isPure then capturesAndResult(typ) else typ()
if token == TLARROW then
for case ValDef(_, tpt, _) <- params do
if isByNameType(tpt) then
Expand All @@ -1585,98 +1588,93 @@ object Parsers {
Function(params, resultType)
}

var isValParamList = false
def typeRest(t: Tree) = in.token match
case ARROW | CTXARROW =>
erasedArgs.addOne(false)
functionRest(t :: Nil)
case MATCH =>
matchType(t)
case FORSOME =>
syntaxError(ExistentialTypesNoLongerSupported())
t
case _ if isPureArrow =>
erasedArgs.addOne(false)
functionRest(t :: Nil)
case _ =>
if erasedArgs.contains(true) && !t.isInstanceOf[FunctionWithMods] then
syntaxError(ErasedTypesCanOnlyBeFunctionTypes(), implicitKwPos(start))
t

val t =
if (in.token == LPAREN) {
var isValParamList = false
if in.token == LPAREN then
in.nextToken()
if in.token == RPAREN then
in.nextToken()
if (in.token == RPAREN) {
in.nextToken()
functionRest(Nil)
}
else {
val paramStart = in.offset
def addErased() =
erasedArgs.addOne(isErasedKw)
if isErasedKw then { in.skipToken(); }
addErased()
val ts = in.currentRegion.withCommasExpected {
functionRest(Nil)
else
val paramStart = in.offset
def addErased() =
erasedArgs.addOne(isErasedKw)
if isErasedKw then in.skipToken()
addErased()
val args =
in.currentRegion.withCommasExpected:
funArgType() match
case Ident(name) if name != tpnme.WILDCARD && in.isColon =>
isValParamList = true
def funParam(start: Offset, mods: Modifiers) = {
atSpan(start) {
def funParam(start: Offset, mods: Modifiers) =
atSpan(start):
addErased()
typedFunParam(in.offset, ident(), imods)
}
}
commaSeparatedRest(
typedFunParam(paramStart, name.toTermName, imods),
() => funParam(in.offset, imods))
case t =>
def funParam() = {
addErased()
funArgType()
}
commaSeparatedRest(t, funParam)
}
accept(RPAREN)
if isValParamList || in.isArrow || isPureArrow then
functionRest(ts)
else {
val ts1 = ts.mapConserve { t =>
if isByNameType(t) then
syntaxError(ByNameParameterNotSupported(t), t.span)
stripByNameType(t)
else
t
}
val tuple = atSpan(start) { makeTupleOrParens(ts1) }
infixTypeRest(
refinedTypeRest(
withTypeRest(
annotTypeRest(
simpleTypeRest(tuple)))))
}
}
}
else if (in.token == LBRACKET) {
val start = in.offset
val tparams = typeParamClause(ParamOwner.TypeParam)
if (in.token == TLARROW)
atSpan(start, in.skipToken())(LambdaTypeTree(tparams, toplevelTyp()))
else if (in.token == ARROW || isPureArrow(nme.PUREARROW)) {
val arrowOffset = in.skipToken()
val body = toplevelTyp()
atSpan(start, arrowOffset) {
getFunction(body) match {
case Some(f) =>
PolyFunction(tparams, body)
case None =>
syntaxError(em"Implementation restriction: polymorphic function types must have a value parameter", arrowOffset)
Ident(nme.ERROR.toTypeName)
}
}
}
else { accept(TLARROW); typ() }
}
else if (in.token == INDENT) enclosed(INDENT, typ())
else infixType()

in.token match
case ARROW | CTXARROW =>
erasedArgs.addOne(false)
functionRest(t :: Nil)
case MATCH => matchType(t)
case FORSOME => syntaxError(ExistentialTypesNoLongerSupported()); t
case _ =>
if isPureArrow then
erasedArgs.addOne(false)
functionRest(t :: Nil)
def funArg() =
erasedArgs.addOne(false)
funArgType()
commaSeparatedRest(t, funArg)
accept(RPAREN)
if isValParamList || in.isArrow || isPureArrow then
functionRest(args)
else
if (erasedArgs.contains(true) && !t.isInstanceOf[FunctionWithMods])
syntaxError(ErasedTypesCanOnlyBeFunctionTypes(), implicitKwPos(start))
t
val args1 = args.mapConserve: t =>
if isByNameType(t) then
syntaxError(ByNameParameterNotSupported(t), t.span)
stripByNameType(t)
else
t
val tuple = atSpan(start):
makeTupleOrParens(args1)
typeRest:
infixTypeRest:
refinedTypeRest:
withTypeRest:
annotTypeRest:
simpleTypeRest(tuple)
else if in.token == LBRACKET then
val start = in.offset
val tparams = typeParamClause(ParamOwner.TypeParam)
if in.token == TLARROW then
atSpan(start, in.skipToken()):
LambdaTypeTree(tparams, toplevelTyp())
else if in.token == ARROW || isPureArrow(nme.PUREARROW) then
val arrowOffset = in.skipToken()
val body = toplevelTyp()
atSpan(start, arrowOffset):
getFunction(body) match
case Some(f) =>
PolyFunction(tparams, body)
case None =>
syntaxError(em"Implementation restriction: polymorphic function types must have a value parameter", arrowOffset)
Ident(nme.ERROR.toTypeName)
else
accept(TLARROW)
typ()
else if in.token == INDENT then
enclosed(INDENT, typ())
else
typeRest(infixType())
end typ

private def makeKindProjectorTypeDef(name: TypeName): TypeDef = {
Expand Down Expand Up @@ -1713,7 +1711,7 @@ object Parsers {
private def implicitKwPos(start: Int): Span =
Span(start, start + nme.IMPLICITkw.asSimpleName.length)

/** TypedFunParam ::= id ':' Type */
/** TypedFunParam ::= [`erased`] id ':' Type */
def typedFunParam(start: Offset, name: TermName, mods: Modifiers = EmptyModifiers): ValDef =
atSpan(start) {
acceptColon()
Expand Down Expand Up @@ -2068,7 +2066,7 @@ object Parsers {
*/
def paramType(): Tree = paramTypeOf(paramValueType)

/** ParamValueType ::= [`into`] Type [`*']
/** ParamValueType ::= Type [`*']
*/
def paramValueType(): Tree = {
val t = maybeInto(toplevelTyp)
Expand Down Expand Up @@ -2425,7 +2423,7 @@ object Parsers {
Match(t, inBracesOrIndented(caseClauses(() => caseClause())))
}

/** `match' `{' TypeCaseClauses `}'
/** `match' <<< TypeCaseClauses >>>
*/
def matchType(t: Tree): MatchTypeTree =
atSpan(startOffset(t), accept(MATCH)) {
Expand All @@ -2435,7 +2433,7 @@ object Parsers {
/** FunParams ::= Bindings
* | id
* | `_'
* Bindings ::= `(' [[‘erased’] Binding {`,' Binding}] `)'
* Bindings ::= `(' [Binding {`,' Binding}] `)'
*/
def funParams(mods: Modifiers, location: Location): List[Tree] =
if in.token == LPAREN then
Expand Down Expand Up @@ -3173,7 +3171,7 @@ object Parsers {
* | AccessModifier
* | override
* | opaque
* LocalModifier ::= abstract | final | sealed | open | implicit | lazy | erased | inline | transparent
* LocalModifier ::= abstract | final | sealed | open | implicit | lazy | inline | transparent | infix | erased
*/
def modifiers(allowed: BitSet = modifierTokens, start: Modifiers = Modifiers()): Modifiers = {
@tailrec
Expand Down
3 changes: 1 addition & 2 deletions compiler/src/dotty/tools/dotc/transform/Recheck.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,13 @@ import ast.*
import Names.Name
import Phases.Phase
import DenotTransformers.{DenotTransformer, IdentityDenotTransformer, SymTransformer}
import NamerOps.{methodType, linkConstructorParams}
import NamerOps.linkConstructorParams
import NullOpsDecorator.stripNull
import typer.ErrorReporting.err
import typer.ProtoTypes.*
import typer.TypeAssigner.seqLitType
import typer.ConstFold
import typer.ErrorReporting.{Addenda, NothingToAdd}
import NamerOps.methodType
import config.Printers.recheckr
import util.Property
import StdNames.nme
Expand Down
36 changes: 24 additions & 12 deletions docs/_docs/internals/syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ productions map to AST nodes.
The following description of Scala tokens uses literal characters `‘c’` when
referring to the ASCII fragment `\u0000` – `\u007F`.

Informal descriptions are typeset as `“some comment”`.

## Lexical Syntax

The lexical syntax of Scala is given by the following grammar in EBNF form:
Expand Down Expand Up @@ -99,7 +101,10 @@ semi ::= ‘;’ | nl {nl}

## Optional Braces

The lexical analyzer also inserts `indent` and `outdent` tokens that represent regions of indented code [at certain points](../reference/other-new-features/indentation.md)
The principle of optional braces is that any keyword that can be followed by `{` can also be followed by an indented block, without needing an intervening `:`.
(Allowing an optional `:` would be counterproductive since it would introduce several ways to do the same thing.)

The lexical analyzer inserts `indent` and `outdent` tokens that represent regions of indented code [at certain points](./other-new-features/indentation.md).
odersky marked this conversation as resolved.
Show resolved Hide resolved

In the context-free productions below we use the notation `<<< ts >>>`
to indicate a token sequence `ts` that is either enclosed in a pair of braces `{ ts }` or that constitutes an indented region `indent ts outdent`. Analogously, the
Expand Down Expand Up @@ -201,14 +206,13 @@ SimpleType1 ::= id
Singleton ::= SimpleRef
| SimpleLiteral
| Singleton ‘.’ id
FunArgType ::= [`erased`] Type
| [`erased`] ‘=>’ Type PrefixOp(=>, t)
FunArgType ::= Type
EugeneFlesselle marked this conversation as resolved.
Show resolved Hide resolved
| ‘=>’ Type PrefixOp(=>, t)
FunArgTypes ::= FunArgType { ‘,’ FunArgType }
ParamType ::= [‘=>’] ParamValueType
ParamValueType ::= [‘into’] ExactParamType Into(t)
ExactParamType ::= ParamValueType [‘*’] PostfixOp(t, "*")
ParamValueType ::= IntoType [‘*’] PostfixOp(t, "*")
odersky marked this conversation as resolved.
Show resolved Hide resolved
TypeArgs ::= ‘[’ Types ‘]’ ts
Refinement ::= :<<< [RefineDef] {semi [RefineDef]} >>> ds
Refinement ::= :<<< [RefineDef] {semi [RefineDcl]} >>> ds
EugeneFlesselle marked this conversation as resolved.
Show resolved Hide resolved
TypeBounds ::= [‘>:’ Type] [‘<:’ Type] TypeBoundsTree(lo, hi)
TypeParamBounds ::= TypeBounds {‘:’ Type} ContextBounds(typeBounds, tps)
Types ::= Type {‘,’ Type}
Expand All @@ -223,7 +227,7 @@ BlockResult ::= FunParams (‘=>’ | ‘?=>’) Block
| HkTypeParamClause ‘=>’ Block
| Expr1
FunParams ::= Bindings
| [`erased`] id
| id
| ‘_’
Expr1 ::= [‘inline’] ‘if’ ‘(’ Expr ‘)’ {nl} Expr [[semi] ‘else’ Expr] If(Parens(cond), thenp, elsep?)
| [‘inline’] ‘if’ Expr ‘then’ Expr [[semi] ‘else’ Expr] If(cond, thenp, elsep?)
Expand Down Expand Up @@ -272,7 +276,7 @@ ColonArgument ::= colon [LambdaStart]
LambdaStart ::= FunParams (‘=>’ | ‘?=>’)
| HkTypeParamClause ‘=>’
Quoted ::= ‘'’ ‘{’ Block ‘}’
| ‘'’ ‘[’ Type ‘]’
| ‘'’ ‘[’ TypeBlock ‘]’
ExprSplice ::= spliceId -- if inside quoted block
| ‘$’ ‘{’ Block ‘}’ -- unless inside quoted pattern
| ‘$’ ‘{’ Pattern ‘}’ -- when inside quoted pattern
Expand All @@ -294,6 +298,8 @@ BlockStat ::= Import
| Extension
| Expr1
| EndMarker
TypeBlock ::= {TypeBlockStat semi} Type
TypeBlockStat ::= ‘type’ {nl} TypeDcl

ForExpr ::= ‘for’ ‘(’ Enumerators0 ‘)’ {nl} [‘do‘ | ‘yield’] Expr ForYield(enums, expr) / ForDo(enums, expr)
| ‘for’ ‘{’ Enumerators0 ‘}’ {nl} [‘do‘ | ‘yield’] Expr
Expand Down Expand Up @@ -376,8 +382,8 @@ Param ::= id ‘:’ ParamType [‘=’ Expr]

### Bindings and Imports
```ebnf
Bindings ::= ‘(’[`erased`] [Binding {‘,’ [`erased`] Binding}] ‘)’
Binding ::= (id | ‘_’) [‘:’ Type] ValDef(_, id, tpe, EmptyTree)
Bindings ::= ‘(’ [Binding {‘,’ Binding}] ‘)’
Binding ::= [`erased`] (id | ‘_’) [‘:’ Type] ValDef(_, id, tpe, EmptyTree)

Modifier ::= LocalModifier
| AccessModifier
Expand All @@ -390,6 +396,10 @@ LocalModifier ::= ‘abstract’
| ‘implicit’
| ‘lazy’
| ‘inline’
| ‘transparent’
| ‘infix’
| ‘erased’

AccessModifier ::= (‘private’ | ‘protected’) [AccessQualifier]
AccessQualifier ::= ‘[’ id ‘]’

Expand All @@ -414,9 +424,11 @@ EndMarkerTag ::= id | ‘if’ | ‘while’ | ‘for’ | ‘match’ |

### Definitions
```ebnf
RefineDef ::= ‘val’ ValDef
| ‘def’ DefDef
RefineDcl ::= ‘val’ ValDcl
| ‘def’ DefDcl
| ‘type’ {nl} TypeDef
ValDcl ::= ids ‘:’ Type
DefDcl ::= DefSig ‘:’ Type

Def ::= ‘val’ PatDef
| ‘var’ PatDef
Expand Down
Loading
Loading