Scala 3 문법 요약
Scala 3 문법 요약 (Syntax Summary)
Scala 3의 문법을 토큰과 문맥 자유 문법(Context-free Syntax) 두 층위로 정리한 요약이에요. 공식 레퍼런스의 문법 정의를 그대로 옮겨 둔 문서라, 자세한 문법 규칙이 필요할 때 펼쳐 보기 좋아요.
본문
다음 Scala 토큰 설명에서 문자 'c'는 ASCII 구간 \u0000–\u007F를 가리킬 때 사용해요. 비형식적인 설명은 "some comment"처럼 표기돼요.
어휘 문법 (Lexical Syntax)
Scala의 어휘 문법은 다음 EBNF 형식의 문법으로 주어져요.
whiteSpace ::= ‘\u0020’ | ‘\u0009’ | ‘\u000D’ | ‘\u000A’
upper ::= ‘A’ | ... | ‘Z’ | ‘$’ and any character in Unicode categories Lu, Lt or Nl,
and any character in Unicode categories Lo and Lm that doesn't have
contributory property Other_Lowercase
lower ::= ‘a’ | ... | ‘z’ | ‘_’ and any character in Unicode category Ll,
and any character in Unicode categories Lo or Lm that has contributory
property Other_Lowercase
letter ::= upper | lower
digit ::= ‘0’ | ... | ‘9’
paren ::= ‘(’ | ‘)’ | ‘[’ | ‘]’ | ‘{’ | ‘}’
delim ::= ‘`’ | ‘'’ | ‘"’ | ‘.’ | ‘;’ | ‘,’
opchar ::= ‘!’ | ‘#’ | ‘%’ | ‘&’ | ‘*’ | ‘+’ | ‘-’ | ‘/’ | ‘:’ |
‘<’ | ‘=’ | ‘>’ | ‘?’ | ‘@’ | ‘\’ | ‘^’ | ‘|’ | ‘~’
and any character in Unicode categories Sm or So
printableChar ::= all characters in [\u0020, \u007E] inclusive
UnicodeEscape ::= ‘\’ ‘u’ {‘u’} hexDigit hexDigit hexDigit hexDigit
hexDigit ::= ‘0’ | ... | ‘9’ | ‘A’ | ... | ‘F’ | ‘a’ | ... | ‘f’
charEscapeSeq ::= ‘\’ (‘b’ | ‘t’ | ‘n’ | ‘f’ | ‘r’ | ‘"’ | ‘'’ | ‘\’)
escapeSeq ::= UnicodeEscape | charEscapeSeq
op ::= opchar {opchar}
varid ::= lower idrest
boundvarid ::= varid
| ‘`’ varid ‘`’
plainid ::= alphaid
| op
id ::= plainid
| ‘`’ { charNoBackQuoteOrNewline | escapeSeq } ‘`’
idrest ::= {letter | digit} [‘_’ op]
quoteId ::= ‘'’ alphaid
spliceId ::= ‘$’ alphaid ;
integerLiteral ::= (decimalNumeral | hexNumeral | binaryNumeral) [‘L’ | ‘l’]
decimalNumeral ::= ‘0’ | digit [{digit | ‘_’} digit]
hexNumeral ::= ‘0’ (‘x’ | ‘X’) hexDigit [{hexDigit | ‘_’} hexDigit]
binaryNumeral ::= ‘0’ (‘b’ | ‘B’) binaryDigit [{binaryDigit | ‘_’} binaryDigit]
floatingPointLiteral
::= [decimalNumeral] ‘.’ digit [{digit | ‘_’} digit] [exponentPart] [floatType]
| decimalNumeral exponentPart [floatType]
| decimalNumeral floatType
exponentPart ::= (‘E’ | ‘e’) [‘+’ | ‘-’] digit [{digit | ‘_’} digit]
floatType ::= ‘F’ | ‘f’ | ‘D’ | ‘d’
booleanLiteral ::= ‘true’ | ‘false’
characterLiteral ::= ‘'’ (charNoQuoteOrNewline | escapeSeq) ‘'’
stringLiteral ::= ‘"’ {stringElement} ‘"’
| ‘"""’ multiLineChars ‘"""’
stringElement ::= charNoDoubleQuoteOrNewline
| escapeSeq
multiLineChars ::= {[‘"’] [‘"’] charNoDoubleQuote} {‘"’}
interpolatedString
::= alphaid ‘"’ {[‘\’] interpolatedStringPart | ‘\\’ | ‘\"’} ‘"’
| alphaid ‘"""’ {[‘"’] [‘"’] char \ (‘"’ | ‘\$’) | escape} {‘"’} ‘"""’
interpolatedStringPart
::= printableChar \ (‘"’ | ‘$’ | ‘\’) | escape
escape ::= ‘\$\$’
| ‘\$"’
| ‘\$’ alphaid
| ‘\$’ BlockExpr
alphaid ::= upper idrest
| varid
comment ::= ‘/*’ “any sequence of characters; nested comments are allowed” ‘*/’
| ‘//’ “any sequence of characters up to end of line”
nl ::= “new line character”
semi ::= ‘;’ | nl {nl}
선택적 중괄호 (Optional Braces)
선택적 중괄호의 원리는, { 뒤에 올 수 있는 키워드라면 중간에 : 없이 들여쓰기 블록(indented block) 뒤에도 올 수 있다는 것이에요. (선택적 :를 허용하는 건 여러 방식으로 같은 일을 하게 만들 뿐이라 바람직하지 않아요.)
어휘 분석기(lexical analyzer)는 특정 지점의 들여쓰기된 코드 구간을 나타내는 indent와 outdent 토큰을 삽입해요.
아래 문맥 자유 생성 규칙에서 <<< ts >>> 표기법은 중괄호 { ts }로 감싸이거나 들여쓰기 구간 indent ts outdent를 이루는 토큰 시퀀스 ts를 나타내요. 비슷하게 :<<< ts >>> 표기는 { ts }로 감싸이거나 콜론 토큰을 따르는 들여쓰기 구간 indent ts outdent를 이루는 토큰 시퀀스 ts를 나타내요.
콜론 토큰은 표준 콜론 ":"으로 읽히는데, 문맥 자유 문법에 따라 콜론이 합법적인 자리에서는 그 대신 생성돼요. 단, 직전 토큰이 영숫자 식별자, 백틱 식별자, 또는 this, super, new, ")", "]" 토큰 중 하나일 때만 그래요.
colon ::= ':' -- with side conditions explained above
<<< ts >>> ::= ‘{’ ts ‘}’
| indent ts outdent
:<<< ts >>> ::= [nl] ‘{’ ts ‘}’
| colon indent ts outdent
키워드 (Keywords)
일반 키워드 (Regular keywords)
abstract case catch class def do else
enum export extends false final finally for
given if implicit import lazy match new
null object override package private protected return
sealed super then throw trait true try
type val var while with yield
: = <- => <: >: #
@ =>> ?=>
소프트 키워드 (Soft keywords)
as derives end extension infix inline opaque open transparent using | * + -
소프트 키워드가 어디에서 인식되는지에 대한 추가 세부 사항은 소프트 키워드에 관한 별도 섹션을 참고하세요.
문맥 자유 문법 (Context-free Syntax)
Scala의 문맥 자유 문법은 다음 EBNF 문법으로 주어져요.
리터럴과 경로 (Literals and Paths)
SimpleLiteral ::= [‘-’] integerLiteral
| [‘-’] floatingPointLiteral
| booleanLiteral
| characterLiteral
| stringLiteral
Literal ::= SimpleLiteral
| interpolatedStringLiteral
| symbolLiteral
| ‘null’
QualId ::= id {‘.’ id}
ids ::= id {‘,’ id}
SimpleRef ::= id
| [id ‘.’] ‘this’
| [id ‘.’] ‘super’ [ClassQualifier] ‘.’ id
ClassQualifier ::= ‘[’ id ‘]’
타입 (Types)
Type ::= FunType
| TypTypeParamClause ‘=>>’ Type
| MatchType
| InfixType
FunType ::= FunTypeArgs (‘=>’ | ‘?=>’) Type
| TypTypeParamClause '=>' Type
FunTypeArgs ::= InfixType
| ‘(’ [ FunArgTypes ] ‘)’
| FunParamClause
FunParamClause ::= ‘(’ TypedFunParam {‘,’ TypedFunParam } ‘)’
TypedFunParam ::= id ‘:’ Type
MatchType ::= InfixType `match` <<< TypeCaseClauses >>>
InfixType ::= RefinedType {id [nl] RefinedType}
RefinedType ::= AnnotType {[nl] Refinement}
AnnotType ::= SimpleType {Annotation}
SimpleType ::= SimpleLiteral
| ‘?’ TypeBounds
| id
| Singleton ‘.’ id
| Singleton ‘.’ ‘type’
| ‘(’ [Types] ‘)’
| ‘(’ NameAndType {‘,’ NameAndType} ‘)’
| Refinement
| SimpleType TypeArgs
| SimpleType ‘#’ id
Singleton ::= SimpleRef
| SimpleLiteral
| Singleton ‘.’ id
FunArgType ::= Type
| ‘=>’ Type
FunArgTypes ::= FunArgType { ‘,’ FunArgType }
ParamType ::= [‘=>’] ParamValueType
ParamValueType ::= Type [‘*’]
TypeArgs ::= ‘[’ Types ‘]’
Refinement ::= :<<< [RefineDcl] {semi [RefineDcl]} >>>
TypeBounds ::= [‘>:’ Type] [‘<:’ Type]
TypeAndCtxBounds ::= TypeBounds [':' ContextBounds]
ContextBounds ::= ContextBound
| ContextBound ':' ContextBounds -- to be deprecated
| '{' ContextBound {',' ContextBound} '}'
ContextBound ::= Type ['as' id]
Types ::= Type {‘,’ Type}
표현식 (Expressions)
Expr ::= FunParams (‘=>’ | ‘?=>’) Expr
| TypTypeParamClause ‘=>’ Expr
| Expr1
BlockResult ::= FunParams (‘=>’ | ‘?=>’) Block
| TypTypeParamClause ‘=>’ Block
| Expr1
FunParams ::= Bindings
| id
| ‘_’
Expr1 ::= [‘inline’] ‘if’ ‘(’ Expr ‘)’ {nl} Expr [[semi] ‘else’ Expr]
| [‘inline’] ‘if’ Expr ‘then’ Expr [[semi] ‘else’ Expr]
| ‘while’ ‘(’ Expr ‘)’ {nl} Expr
| ‘while’ Expr ‘do’ Expr
| ‘try’ Expr Catches [‘finally’ Expr]
| ‘try’ Expr [‘finally’ Expr]
| ‘throw’ Expr
| ‘return’ [Expr]
| ForExpr
| [SimpleExpr ‘.’] id ‘=’ Expr
| PrefixOperator SimpleExpr ‘=’ Expr
| InfixExpr id [nl] `=' Expr -- only if language.postfixOps is enabled
| SimpleExpr ArgumentExprs ‘=’ Expr
| PostfixExpr [Ascription]
| ‘inline’ InfixExpr MatchClause
Ascription ::= ‘:’ InfixType
| ‘:’ Annotation {Annotation}
Catches ::= ‘catch’ (Expr | ExprCaseClause)
PostfixExpr ::= InfixExpr [id] -- only if language.postfixOperators is enabled
InfixExpr ::= PrefixExpr
| InfixExpr id [nl] InfixExpr
| InfixExpr id ColonArgument
| InfixExpr MatchClause
MatchClause ::= ‘match’ <<< CaseClauses >>>
PrefixExpr ::= [PrefixOperator] SimpleExpr
PrefixOperator ::= ‘-’ | ‘+’ | ‘~’ | ‘!’ -- unless backquoted
SimpleExpr ::= SimpleRef
| Literal
| ‘_’
| BlockExpr
| ExprSplice
| Quoted
| quoteId -- only inside splices
| ‘new’ ConstrApp {‘with’ ConstrApp} [TemplateBody]
| ‘new’ TemplateBody
| ‘(’ [ExprsInParens] ‘)’
| ‘(’ NamedExprInParens {‘,’ NamedExprInParens} ‘)’
| SimpleExpr ‘.’ id
| SimpleExpr ‘.’ MatchClause
| SimpleExpr TypeArgs
| SimpleExpr ArgumentExprs
| SimpleExpr ColonArgument
ColonArgument ::= colon [LambdaStart]
indent (CaseClauses | Block) outdent
LambdaStart ::= FunParams (‘=>’ | ‘?=>’)
| TypTypeParamClause ‘=>’
Quoted ::= ‘'’ ‘{’ Block ‘}’
| ‘'’ ‘[’ TypeBlock ‘]’
ExprSplice ::= spliceId -- if inside quoted block
| ‘$’ ‘{’ Block ‘}’ -- unless inside quoted pattern
| ‘$’ ‘{’ Pattern ‘}’ -- when inside quoted pattern
ExprsInParens ::= ExprInParens {‘,’ ExprInParens}
ExprInParens ::= PostfixExpr ‘:’ Type | Expr
ParArgumentExprs ::= ‘(’ [ExprsInParens] ‘)’
| ‘(’ ‘using’ ExprsInParens ‘)’
| ‘(’ [ExprsInParens ‘,’] PostfixExpr ‘*’ ‘)’
NamedExprInParens ::= id ‘=’ ExprInParens
ArgumentExprs ::= ParArgumentExprs
| BlockExpr
BlockExpr ::= <<< (CaseClauses | Block) >>>
Block ::= {BlockStat semi} [BlockResult]
BlockStat ::= Import
| {Annotation {nl}} {LocalModifier} Def
| Extension
| Expr1
| EndMarker
TypeBlock ::= {TypeBlockStat semi} Type
TypeBlockStat ::= ‘type’ {nl} TypeDef
ForExpr ::= ‘for’ ‘(’ Enumerators0 ‘)’ {nl} [‘do‘ | ‘yield’] Expr
| ‘for’ ‘{’ Enumerators0 ‘}’ {nl} [‘do‘ | ‘yield’] Expr
| ‘for’ Enumerators0 (‘do‘ | ‘yield’) Expr
Enumerators0 ::= {nl} Enumerators [semi]
Enumerators ::= Generator {semi Enumerator | Guard}
Enumerator ::= Generator
| Guard {Guard}
| Pattern1 ‘=’ Expr
Generator ::= [‘case’] Pattern1 ‘<-’ Expr
Guard ::= ‘if’ PostfixExpr
CaseClauses ::= CaseClause { CaseClause }
CaseClause ::= ‘case’ Pattern [Guard] ‘=>’ Block
ExprCaseClause ::= ‘case’ Pattern [Guard] ‘=>’ Expr
TypeCaseClauses ::= TypeCaseClause { TypeCaseClause }
TypeCaseClause ::= ‘case’ (InfixType | ‘_’) ‘=>’ Type [semi]
Pattern ::= Pattern1 { ‘|’ Pattern1 }
Pattern1 ::= PatVar ‘:’ RefinedType
| [‘-’] integerLiteral ‘:’ RefinedType
| [‘-’] floatingPointLiteral ‘:’ RefinedType
| Pattern2
Pattern2 ::= [id ‘@’] InfixPattern
InfixPattern ::= SimplePattern { id [nl] SimplePattern }
SimplePattern ::= PatVar
| Literal
| ‘(’ [Patterns] ‘)’
| Quoted
| SimplePattern1 [TypeArgs] [ArgumentPatterns]
| ‘given’ RefinedType
SimplePattern1 ::= SimpleRef
| SimplePattern1 ‘.’ id
PatVar ::= varid
| ‘_’
NamedPattern ::= id ‘=’ Pattern
Patterns ::= Pattern {‘,’ Pattern}
| NamedPattern {‘,’ NamedPattern}
ArgumentPatterns ::= ‘(’ [Patterns] ‘)’
| ‘(’ [Patterns ‘,’] PatVar ‘*’ ‘)’
타입·값 파라미터 (Type and Value Parameters)
ClsTypeParamClause ::= ‘[’ ClsTypeParam {‘,’ ClsTypeParam} ‘]’
ClsTypeParam ::= {Annotation} [‘+’ | ‘-’] id [HkTypeParamClause] TypeAndCtxBounds
DefTypeParamClause ::= [nl] ‘[’ DefTypeParam {‘,’ DefTypeParam} ‘]’
DefTypeParam ::= {Annotation} id [HkTypeParamClause] TypeAndCtxBounds
TypTypeParamClause ::= ‘[’ TypTypeParam {‘,’ TypTypeParam} ‘]’
TypTypeParam ::= {Annotation} (id | ‘_’) [HkTypeParamClause] TypeBounds
HkTypeParamClause ::= ‘[’ HkTypeParam {‘,’ HkTypeParam} ‘]’
HkTypeParam ::= {Annotation} [‘+’ | ‘-’] (id | ‘_’) [HkTypeParamClause] TypeBounds
ClsParamClauses ::= {ClsParamClause} [[nl] ‘(’ [‘implicit’] ClsParams ‘)’]
ClsParamClause ::= [nl] ‘(’ ClsParams ‘)’
| [nl] ‘(’ ‘using’ (ClsParams | FunArgTypes) ‘)’
ClsParams ::= ClsParam {‘,’ ClsParam}
ClsParam ::= {Annotation} [{Modifier} (‘val’ | ‘var’)] Param
DefParamClauses ::= DefParamClause { DefParamClause } -- and two DefTypeParamClause cannot be adjacent
DefParamClause ::= DefTypeParamClause
| DefTermParamClause
| UsingParamClause
ConstrParamClauses ::= ConstrParamClause {ConstrParamClause}
ConstrParamClause ::= DefTermParamClause
| UsingParamClause
DefTermParamClause ::= [nl] ‘(’ [DefTermParams] ‘)’
UsingParamClause ::= [nl] ‘(’ ‘using’ (DefTermParams | FunArgTypes) ‘)’
DefImplicitClause ::= [nl] ‘(’ ‘implicit’ DefTermParams ‘)’
DefTermParams ::= DefTermParam {‘,’ DefTermParam}
DefTermParam ::= {Annotation} [‘inline’] Param
Param ::= id ‘:’ ParamType [‘=’ Expr]
바인딩과 import (Bindings and Imports)
Bindings ::= ‘(’ [Binding {‘,’ Binding}] ‘)’
Binding ::= (id | ‘_’) [‘:’ Type]
Modifier ::= LocalModifier
| AccessModifier
| ‘override’
| ‘opaque’
LocalModifier ::= ‘abstract’
| ‘final’
| ‘sealed’
| ‘open’
| ‘implicit’
| ‘lazy’
| ‘inline’
| ‘transparent’
| ‘infix’
AccessModifier ::= (‘private’ | ‘protected’) [AccessQualifier]
AccessQualifier ::= ‘[’ id ‘]’
Annotation ::= ‘@’ SimpleType {ParArgumentExprs}
Import ::= ‘import’ ImportExpr {‘,’ ImportExpr}
Export ::= ‘export’ ImportExpr {‘,’ ImportExpr}
ImportExpr ::= SimpleRef {‘.’ id} ‘.’ ImportSpec
| SimpleRef ‘as’ id
ImportSpec ::= NamedSelector
| WildCardSelector
| ‘{’ ImportSelectors) ‘}’
NamedSelector ::= id [‘as’ (id | ‘_’)]
WildCardSelector ::= ‘*’ | ‘given’ [InfixType]
ImportSelectors ::= NamedSelector [‘,’ ImportSelectors]
| WildCardSelector {‘,’ WildCardSelector}
EndMarker ::= ‘end’ EndMarkerTag -- when followed by EOL
EndMarkerTag ::= id | ‘if’ | ‘while’ | ‘for’ | ‘match’ | ‘try’
| ‘new’ | ‘this’ | ‘given’ | ‘extension’ | ‘val’
선언과 정의 (Declarations and Definitions)
RefineDcl ::= ‘val’ ValDcl
| ‘def’ DefDcl
| ‘var’ ValDcl
| ‘type’ {nl} TypeDef
ValDcl ::= ids ‘:’ Type
DefDcl ::= DefSig ‘:’ Type
Def ::= ‘val’ PatDef
| ‘var’ PatDef
| ‘def’ DefDef
| ‘type’ {nl} TypeDef
| TmplDef
PatDef ::= ids [‘:’ Type] [‘=’ Expr]
| Pattern2 [‘:’ Type] [‘=’ Expr] PatDef(_, pats, tpe?, expr)
DefDef ::= DefSig [‘:’ Type] [‘=’ Expr] DefDef(_, name, paramss, tpe, expr)
| ‘this’ ConstrParamClauses [DefImplicitClause] ‘=’ ConstrExpr DefDef(_, <init>, vparamss, EmptyTree, expr | Block)
DefSig ::= id [DefParamClauses] [DefImplicitClause]
TypeDef ::= id [HkTypeParamClause] {FunParamClause}TypeBounds TypeDefTree(_, name, tparams, bound
[‘=’ Type]
TmplDef ::= ([‘case’] ‘class’ | ‘trait’) ClassDef
| [‘case’] ‘object’ ObjectDef
| ‘enum’ EnumDef
| 'given' (GivenDef | OldGivenDef)
ClassDef ::= id ClassConstr [Template]
ClassConstr ::= [ClsTypeParamClause] [ConstrMods] ClsParamClauses
ConstrMods ::= {Annotation} [AccessModifier]
ObjectDef ::= id [Template]
EnumDef ::= id ClassConstr InheritClauses EnumBody
GivenDef ::= [id ':'] GivenSig
GivenSig ::= GivenImpl
| '(' ')' '=>' GivenImpl
| GivenConditional '=>' GivenSig
GivenImpl ::= GivenType ([‘=’ Expr] | TemplateBody)
| ConstrApps TemplateBody
GivenConditional ::= DefTypeParamClause
| DefTermParamClause
| '(' FunArgTypes ')'
| GivenType
GivenType ::= AnnotType1 {id [nl] AnnotType1}
OldGivenDef ::= [OldGivenSig] (AnnotType [‘=’ Expr] | StructuralInstance) -- syntax up to Scala 3.5, to be deprecated in the future
OldGivenSig ::= [id] [DefTypeParamClause] {UsingParamClause} ‘:’ -- one of `id`, `DefTypeParamClause`, `UsingParamClause` must be present
StructuralInstance ::= ConstrApp {‘with’ ConstrApp} [‘with’ WithTemplateBody]
Extension ::= ‘extension’ [DefTypeParamClause] {UsingParamClause}
‘(’ DefTermParam ‘)’ {UsingParamClause} ExtMethods
ExtMethods ::= ExtMethod | [nl] <<< ExtMethod {semi ExtMethod} >>>
ExtMethod ::= {Annotation [nl]} {Modifier} ‘def’ DefDef
| Export
Template ::= InheritClauses [TemplateBody]
InheritClauses ::= [‘extends’ ConstrApps] [‘derives’ QualId {‘,’ QualId}]
ConstrApps ::= ConstrApp ({‘,’ ConstrApp} | {‘with’ ConstrApp})
ConstrApp ::= SimpleType {Annotation} {ParArgumentExprs}
ConstrExpr ::= SelfInvocation
| <<< SelfInvocation {semi BlockStat} >>>
SelfInvocation ::= ‘this’ ArgumentExprs {ArgumentExprs}
WithTemplateBody ::= <<< [SelfType] TemplateStat {semi TemplateStat} >>>
TemplateBody ::= :<<< [SelfType] TemplateStat {semi TemplateStat} >>>
TemplateStat ::= Import
| Export
| {Annotation [nl]} {Modifier} Def
| Extension
| Expr1
| EndMarker
|
SelfType ::= id [‘:’ InfixType] ‘=>’
| ‘this’ ‘:’ InfixType ‘=>’
EnumBody ::= :<<< [SelfType] EnumStat {semi EnumStat} >>>
EnumStat ::= TemplateStat
| {Annotation [nl]} {Modifier} EnumCase
EnumCase ::= ‘case’ (id ClassConstr [‘extends’ ConstrApps]] | ids)
TopStats ::= TopStat {semi TopStat}
TopStat ::= Import
| Export
| {Annotation [nl]} {Modifier} Def
| Extension
| Packaging
| PackageObject
| EndMarker
|
Packaging ::= ‘package’ QualId :<<< TopStats >>>
PackageObject ::= ‘package’ ‘object’ ObjectDef
CompilationUnit ::= {‘package’ QualId semi} TopStats