Icon

The documentation for Kotlin is now located on the new site. This page is kept for historical reasons

Skip to end of metadata
Go to start of metadata
Icon

The documentation for Kotlin is now located on the new site. This page is kept for historical reasons

Contents

Notation

This section informally explains the grammar notation used below.

Symbols and naming

Terminal symbol names start with an uppercase letter, e.g. SimpleName
Nonterminal symbol names start with lowercase letter, e.g. kotlinFile
Each production starts with a colon (:)
Symbol definitions may have many productions and are terminated by a semicolon (;)
Symbol definitions may be prepended with attributes, e.g. start attribute denotes a start symbol

EBNF expressions

Operator | denotes alternative
Operator * denotes iteration (zero or more)
Operator + denotes iteration (one or more)
Operator ? denotes option (zero or one)
alpha{beta} denotes a nonempty beta-separated list of alpha's

Semicolons

Kotlin provides "semicolon inference": syntactically, subsentences (e.g., statements, declarations etc) are separated by
the pseudo-token SEMI, which stands for "semicolon or newline". In most cases, there's no need for semicolons in
Kotlin code.

Syntax

Relevant pages: Namespaces

start
kotlinFile
  : #preamble #toplevelObject*
  ;

start
script
  : #preamble #expression*
  ;

[Used by #script, #kotlinFile]
preamble
  : #packageHeader? #import*
  ;

[Used by #preamble]
packageHeader
  : #modifiers "package" #SimpleName{"."} #SEMI?
  ;

[Used by #preamble, #package]
import
  : "import" #SimpleName{"."} ("." "*" | "as" #SimpleName)? #SEMI?
  ;

See Imports

[Used by #package, #kotlinFile]
toplevelObject
  : #package
  : #class
  : #object
  : #function
  : #property
  : #typedef
  ;

[Used by #toplevelObject]
package
  : "package" #SimpleName{"."} "{"
       #import*
       #toplevelObject*
    "}"
  ;

See Namespaces

undocumented
[Used by #memberDeclaration, #declaration, #toplevelObject]
typedef
  : #modifiers "type" #SimpleName (#typeParameters #typeConstraints)? "=" #type
  ;

Classes

See Classes and Inheritance

[Used by #memberDeclaration, #declaration, #toplevelObject]
class
  : #modifiers ("class" | "trait") #SimpleName
      #typeParameters?
      #modifiers ("(" #functionParameter{","} ")")?
      (":" #annotations #delegationSpecifier{","})?
      #typeConstraints
      (#classBody? | #enumClassBody)
  ;

[Used by #objectLiteral, #enumEntry, #class, #object]
classBody
  : ("{" #memberDeclaration* "}")?
  ;

[Used by #objectLiteral, #class, #object]
delegationSpecifier
  : #constructorInvocation 
  : #userType
  : #explicitDelegation
  ;

[Used by #delegationSpecifier]
explicitDelegation
  : #userType "by" #expression 
  ;

[Used by #class, #property, #typedef, #function]
typeParameters
  : "<" #typeParameter{","} ">"
  ;

[Used by #typeParameters]
typeParameter
  : #modifiers #SimpleName (":" #userType)?
  ;

See Generic classes

[Used by #class, #property, #typedef, #function]
typeConstraints
  : ("where" #typeConstraint{","})?
  ;

[Used by #typeConstraints]
typeConstraint
  : #annotations #SimpleName ":" #type
  : #annotations "class" "object" #SimpleName ":" #type
  ;

See Generic constraints

Class members

[Used by #enumClassBody, #classBody]
memberDeclaration
  : #classObject
  : #object
  : #function
  : #property
  : #class
  : #typedef
  : #anonymousInitializer
  ;

[Used by #memberDeclaration]
anonymousInitializer
  : #block
  ;

[Used by #memberDeclaration]
classObject
  : #modifiers "class" #object
  ;

See Class objects

[Used by #function]
valueParameters
  : "(" #functionParameter{","}? ")" 
  ;

[Used by #valueParameters, #class]
functionParameter
  : #modifiers ("val" | "var")? #parameter ("=" #expression)?
  ;

[Used by #enumEntry]
initializer
  : #annotations "this" #valueArguments
  : #annotations #constructorInvocation 
  ;

[Used by #catchBlock, #anonymousInitializer, #functionBody, #try, #finallyBlock]
block
  : "{" #statements "}"
  ;

[Used by #memberDeclaration, #declaration, #toplevelObject]
function
  : #modifiers "fun" #typeParameters?
      (#type "." | #annotations)?
      #SimpleName
      #typeParameters? #valueParameters (":" #type)?
      #typeConstraints
      #functionBody?
  ;

[Used by #getter, #setter, #function]
functionBody
  : #block
  : "=" #expression
  ;

[Used by #for, #property, #multipleVariableDeclarations]
variableDeclarationEntry
  : #SimpleName (":" #type)?
  ;

[Used by #for, #property]
multipleVariableDeclarations
  : "(" #variableDeclarationEntry{","} ")"
  ;

[Used by #memberDeclaration, #declaration, #toplevelObject]
property
  : #modifiers ("val" | "var")
      #typeParameters? (#type "." | #annotations)?
      (#multipleVariableDeclarations | #variableDeclarationEntry)
      #typeConstraints
      ("by" | "=" #expression #SEMI?)?
      (#getter? #setter? | #setter? #getter?) #SEMI?
  ;

See Properties and Fields

[Used by #property]
getter
  : #modifiers "get"
  : #modifiers "get" "(" ")" (":" #type)? #functionBody
  ;

[Used by #property]
setter
  : #modifiers "set"
  : #modifiers "set" "(" #modifiers (#SimpleName | #parameter) ")" #functionBody
  ;

[Used by #functionType, #setter, #functionParameter]
parameter
  : #SimpleName ":" #type
  ;

[Used by #memberDeclaration, #declaration, #toplevelObject, #classObject]
object
  : "object" #SimpleName (":" #delegationSpecifier{","})? #classBody? 

See Object expressions and Declarations

Enum classes

See Enum classes

[Used by #class]
enumClassBody
  : "{" (#enumEntry | #memberDeclaration)* "}"
  ;

[Used by #enumClassBody]
enumEntry
  : #modifiers #SimpleName (":" #initializer{","})? #classBody?
  ;

Types

See Types

[Used by #isRHS, #simpleUserType, #getter, #atomicExpression, #property, #typeArguments, #typedef, #function, #functionLiteral, #parameter, #functionType, #variableDeclarationEntry, #typeConstraint]
type
  : #annotations #typeDescriptor

[Used by #nullableType, #typeDescriptor, #type]
typeDescriptor
  : "(" #typeDescriptor ")"
  : #selfType
  : #functionType
  : #userType
  : #nullableType
  ;

[Used by #typeDescriptor]
nullableType
  : #typeDescriptor "?"

[Used by #typeDescriptor]
selfType
  : "This"
  ;

[Used by #typeParameter, #catchBlock, #callableReference, #typeDescriptor, #delegationSpecifier, #constructorInvocation, #explicitDelegation]
userType
  : ("package" ".")? #simpleUserType{"."}
  ;

[Used by #userType]
simpleUserType
  : #SimpleName ("<" (#optionalProjection #type | "*"){","} ">")?
  ;

[Used by #simpleUserType]
optionalProjection
  : #varianceAnnotation
  ;

[Used by #typeDescriptor]
functionType
  : (#type ".")? "(" (#parameter | #modifiers  #type){","} ")" "->" #type?
  ;

Control structures

See Control structures

[Used by #atomicExpression]
if
  : "if" "(" #expression ")" #expression #SEMI? ("else" #expression)?
  ;

[Used by #atomicExpression]
try
  : "try" #block #catchBlock* #finallyBlock?
  ;

[Used by #try]
catchBlock
  : "catch" "(" #annotations #SimpleName ":" #userType ")" #block
  ;

[Used by #try]
finallyBlock
  : "finally" #block
  ;

[Used by #atomicExpression]
loop
  : #for
  : #while
  : #doWhile
  ;

[Used by #loop]
for
  : "for" "(" #annotations ("val" | "var")? (#multipleVariableDeclarations | #variableDeclarationEntry) "in" #expression ")" #expression
  ;

[Used by #loop]
while
  : "while" "(" #expression ")" #expression
  ;

[Used by #loop]
doWhile
  : "do" #expression "while" "(" #expression ")"
  ;

Expressions

See Expressions

Precedence

Precedence

Title

Symbols

Highest

Postfix

++, --, ., ?., ?

 

Prefix

-, +, ++, --, !, @label, @, @@

 

Type RHS

:, as, as?

 

Multiplicative

*, /, %

 

Additive

+, -

 

Range

..

 

Infix function

SimpleName

 

Elvis

?:

 

Named checks

in, !in, is, !is

 

Comparison

<, >, <=, >=

 

Equality

==, !==

 

Conjunction

&&

 

Disjunction

||

Lowest

Assignment

=, +=, -=, *=, /=, %=

Rules

[Used by #for, #atomicExpression, #longTemplate, #whenCondition, #functionBody, #doWhile, #property, #script, #explicitDelegation, #jump, #while, #whenEntry, #arrayAccess, #statement, #if, #when, #valueArguments, #functionParameter]
expression
  : #disjunction (#assignmentOperator #disjunction)*
  ;

[Used by #expression]
disjunction
  : #conjunction ("||" #conjunction)*
  ;

[Used by #disjunction]
conjunction
  : #equalityComparison ("&&" #equalityComparison)*
  ;

[Used by #conjunction]
equalityComparison
  : #comparison (#equalityOperation #comparison)*
  ;

[Used by #equalityComparison]
comparison
  : #namedInfix (#comparisonOperation #namedInfix)*
  ;

[Used by #comparison]
namedInfix
  : #elvisExpression (#inOperation #elvisExpression)*
  : #elvisExpression (#isOperation #isRHS)?
  ;

[Used by #namedInfix]
elvisExpression
  : #infixFunctionCall ("?:" #infixFunctionCall)*
  ;

[Used by #elvisExpression]
infixFunctionCall
  : #rangeExpression (#SimpleName #rangeExpression)*
  ;

[Used by #infixFunctionCall]
rangeExpression
  : #additiveExpression (".." #additiveExpression)*
  ;

[Used by #rangeExpression]
additiveExpression
  : #multiplicativeExpression (#additiveOperation #multiplicativeExpression)*
  ;

[Used by #additiveExpression]
multiplicativeExpression
  : #typeRHS (#multiplicativeOperation #typeRHS)*
  ;

[Used by #multiplicativeExpression]
typeRHS
  : #prefixUnaryExpression (#typeOperation #prefixUnaryExpression)*
  ;

[Used by #typeRHS]
prefixUnaryExpression
  : #prefixUnaryOperation* #postfixUnaryExpression
  ;

[Used by #prefixUnaryExpression, #postfixUnaryOperation]
postfixUnaryExpression
  : #atomicExpression #postfixUnaryOperation*
  : #callableReference #postfixUnaryOperation*
  ;

[Used by #postfixUnaryExpression]
callableReference
  : #userType? "::" #SimpleName
  ;

[Used by #postfixUnaryExpression]
atomicExpression
  : "(" #expression ")"
  : #literalConstant
  : #functionLiteral
  : "this" #label?
  : "super" ("<" #type ">")? #label?
  : #if
  : #when
  : #try
  : #objectLiteral
  : #jump
  : #loop
  : #SimpleName
  : #FieldName
  : "package" 
  ;

[Used by #callSuffix, #prefixUnaryOperation, #atomicExpression, #jump]
label
  : "@"
  : "@@"
  : #LabelName
  ;

[Used by #atomicExpression]
literalConstant
  : "true" | "false"
  : #stringTemplate
  : #NoEscapeString
  : #IntegerLiteral
  : #HexadecimalLiteral
  : #CharacterLiteral
  : #FloatLiteral
  : "null"
  ;

[Used by #literalConstant]
stringTemplate
  : "\"" #stringTemplateElement* "\""
  ;

[Used by #stringTemplate]
stringTemplateElement
  : (warning) Undeclared! #RegularStringPart
  : (warning) Undeclared! #ShortTemplateEntrySTART (#SimpleName | "this")
  : (warning) Undeclared! #EscapeSequence
  : #longTemplate
  ;

[Used by #stringTemplateElement]
longTemplate
  : "${" #expression "}"
  ;

[Used by #namedInfix, #whenCondition]
isRHS
  : #type
  ;

[Used by #statement]
declaration
  : #function
  : #property
  : #class
  : #typedef
  : #object
  ;

[Used by #statements]
statement
  : #declaration
  : #expression
  ;

[Used by #multiplicativeExpression]
multiplicativeOperation
  : "*" : "/" : "%"
  ;

[Used by #additiveExpression]
additiveOperation
  : "+" : "-"
  ;

[Used by #namedInfix]
inOperation
  : "in" : "!in"
  ;

[Used by #typeRHS]
typeOperation
  : "as" : "as?" : ":"
  ;

[Used by #namedInfix]
isOperation
  : "is" : "!is"
  ;

[Used by #comparison]
comparisonOperation
  : "<" : ">" : ">=" : "<="
  ;

[Used by #equalityComparison]
equalityOperation
  : "!=" : "=="
  ;

[Used by #expression]
assignmentOperator
  : "="
  : "+=" : "-=" : "*=" : "/=" : "%="
  ;

[Used by #prefixUnaryExpression]
prefixUnaryOperation
  : "-" : "+"
  : "++" : "--"
  : "!"  
  : #annotations 
  : #label
  ;

[Used by #postfixUnaryExpression]
postfixUnaryOperation
  : "++" : "--" : "!!"
  : #callSuffix
  : #arrayAccess
  : #memberAccessOperation #postfixUnaryExpression 
  ;

[Used by #constructorInvocation, #postfixUnaryOperation]
callSuffix
  : #typeArguments? #valueArguments (#label? #functionLiteral)
  : #typeArguments (#label? #functionLiteral)
  ;

[Used by #postfixUnaryOperation]
memberAccessOperation
  : "." : "?." : "?"
  ;

[Used by #callSuffix, #annotationEntry]
typeArguments
  : "<" #type{","} ">"
  ;

[Used by #callSuffix, #annotationEntry, #initializer]
valueArguments
  : "(" (#SimpleName "=")? "*"? #expression{","} ")"
  ;

[Used by #atomicExpression]
jump
  : "throw" #expression
  : "return" #label? #expression?
  : "continue" #label?
  : "break" #label?

  ;

[Used by #callSuffix, #atomicExpression]
functionLiteral
  : "{" #statements "}"
  : "{" (#modifiers #SimpleName){","} "->" #statements "}"
  : "{" (#type ".")? "(" (#modifiers #SimpleName (":" #type)?){","} ")" (":" #type)? "->" #statements "}"
  ;

[Used by #block, #functionLiteral]
statements
  : #SEMI* #statement{#SEMI+} #SEMI*
  ;

[Used by #delegationSpecifier, #initializer]
constructorInvocation
  : #userType #callSuffix
  ;

[Used by #postfixUnaryOperation]
arrayAccess
  : "[" #expression{","} "]"
  ;

[Used by #atomicExpression]
objectLiteral
  : "object" (":" #delegationSpecifier{","})? #classBody 
  ;

Pattern matching

See Pattern matching

[Used by #atomicExpression]
when
  : "when" ("(" (#modifiers "val" #SimpleName "=")? #expression ")")? "{"
        #whenEntry*
    "}"
  ;

[Used by #when]
whenEntry
  : #whenCondition{","} "->" #expression #SEMI
  : "else" "->" #expression #SEMI
  ;

[Used by #whenEntry]
whenCondition
  : #expression
  : ("in" | "!in") #expression
  : ("is" | "!is") #isRHS
  ;

Modifiers

[Used by #typeParameter, #getter, #packageHeader, #class, #property, #typedef, #function, #functionLiteral, #functionType, #when, #setter, #enumEntry, #classObject, #functionParameter]
modifiers
  : #modifier*
  ;

[Used by #modifiers]
modifier
  : #classModifier
  : #accessModifier
  : #varianceAnnotation
  : #memberModifier
  : #parameterKind
  : #annotations
  ;

[Used by #modifier]
classModifier
  : "abstract"
  : "final"
  : "enum"
  : "open"
  : "attribute"
  ;

[Used by #modifier]
memberModifier
  : "override"
  : "open"
  : "final"
  : "abstract"
  ;

[Used by #modifier]
accessModifier
  : "private"
  : "protected"
  : "public"
  : "internal"
  ;

[Used by #modifier, #optionalProjection]
varianceAnnotation
  : "in"
  : "out"
  ;

[Used by #modifier]
parameterKind
  : "lazy"
  : "out"
  : "ref"
  ;

Annotations

[Used by #modifier, #catchBlock, #prefixUnaryOperation, #for, #class, #property, #type, #typeConstraint, #function, #initializer]
annotations
  : #annotation*
  ;

[Used by #annotations]
annotation
  : "[" #annotationEntry+ "]"
  : #annotationEntry
  ;

[Used by #annotation]
annotationEntry
  : #SimpleName{"."} #typeArguments? #valueArguments?
  ;

Lexical structure

helper
[Used by #IntegerLiteral, #HexDigit]
Digit
  : ["0".."9"];

[Used by #literalConstant]
IntegerLiteral
  : #Digit+?

[Used by #literalConstant]
FloatLiteral
  : <java double literal>;

helper
[Used by #HexadecimalLiteral]
HexDigit
  : #Digit | ["A".."F""a".."f"];

[Used by #literalConstant]
HexadecimalLiteral
  : "0x" #HexDigit+;

[Used by #literalConstant]
CharacterLiteral
  : <character as in Java>;

See Basic types

StringWithTemplates
  : <single-quoted string, $ can be escaped>;

[Used by #literalConstant]
NoEscapeString
  : <"""-quoted string>;

See String templates

[Used by #whenEntry, #if, #statements, #packageHeader, #property, #import]
SEMI
  : <semicolon or newline>;

[Used by #typeParameter, #package, #LabelName, #packageHeader, #object, #function, #parameter, #callableReference, #FieldName, #when, #variableDeclarationEntry, #setter, #import, #valueArguments, #catchBlock, #simpleUserType, #atomicExpression, #class, #typedef, #infixFunctionCall, #functionLiteral, #annotationEntry, #enumEntry, #stringTemplateElement, #typeConstraint]
SimpleName
  : <java identifier>
  : "`" <java identifier> "`"
  ;

See Java interoperability

[Used by #atomicExpression]
FieldName
  : "$" #SimpleName;

See Properties And Fields

[Used by #label]
LabelName
  : "@" #SimpleName;

See Nonlocal returns and jumps

  • No labels

24 Comments

  1. annotationEntry
    : SimpleName

    Unknown macro: {"."}

    typeArguments? valueArguments?
    ;

    Do you have example annotations that are typed or take arguments?  Apologies if I missed them in the rest of the wiki docs. 

    1. Not yet. But this is coming soon.

  2. Anonymous

    Operator + denotes iteration (one or one)

    Must be: one or more

  3. classBody should be ("{" SEMI* memberDeclaration{SEMI+}? SEMI* "}")? or maybe you could introduce a memberDeclarations production like statements.

  4. Anonymous

    Why optional semicolons, I know it's popular, but isn't it a bit “unscientific” with “some whitespace significance” (I have encountered some problems with automatic statement separation in Groovy) ? Wouldn't it be better to make up your mind and make it purely whitespace-driven (such as Python) or purely whitespace agnostic (such as C) ?

    1. Our motivation is basically that on the one hand, semicolons introduce unnecessary noise, and on the other hand, everybody likes to have their own convention about whitespace. The latter may be overrated, in fact. We'll think about it. Thank you.

      1. Hi.  I'll add my vote for one way or the other. Optional stuff usually ends up causing trouble for beginners and/or tool builders ...  I'll also point out that they are really good for error resynchronization during parsing, but you guys are experts at that given the quality of your recovery in intellij.

  5. typeRHS should be prefixUnaryExpression (typeOperation prefixUnaryExpression)*

    postfixUnaryOperation should be memberAccessOperation postfixUnaryExpression

      1. If I look closer at the memberAccessOperation, I think it is more a binary operation and not an unary one. Am I right? So maybe it's not good to file it under postfixUnaryOperation.

        1. It's a matter of precedence: to put it somewhere else means to lower its precedence.

  6. According to the two examples taken from Object expressions and Declarations:

    val adHoc = object { 
      var x : Int = 0 
      var y : Int = 0 
    } 
    val ab = object : A(1), B("abc") { 
      override val y = 15 
    }

    objectLiteral should be:

    I think the same applies to object. It should be:

  7. I think tupleLiteral should be:

    to support the empty tuple (Unit).

    Another point is that tuplePattern is defined as:

    there is only one SimpleName possible where in tupleLiteral there is one SimpleName per expression. Maybe tuplePattern should be:

    What is the SimpleName doing in tuples?

    1. On the simple names: they are labels, so that you can say something like

      val t = (a = 5, b = 6) 
      print(t.a)

      The grammar for patterns is broken, you are right. I'll fix it.

  8. Possible this is a mistake in the Precedence table:

    Equality operators:

    ==!=====!===

    Because in the grammar I see equalityOperation : "!=" : "==" : "===" : "!=="

    1. We should have removed === and !=== from the grammar.

  9. Is there any grammar for the 'inner' keyword? I can not find any description even on the github.

    1. This grammar is a little outdated. You can look for usages of JetTokens.INNER_KEYWORD in the code, but basically it is just another modifier, same as public or abstract

  10. Isn't elvis operator priority too low? You need to null-check the multiplication/addition result a lot less often than null-check multiplication/addition argument with some default value.

    1. We should think about it. Could you file an issue? Thanks