Skip to end of metadata
Go to start of metadata

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
  :  Undeclared! RegularStringPart
  :  Undeclared! ShortTemplateEntrySTART (SimpleName | "this")
  :  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]

Labels:
None
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. Jul 25, 2011

    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. Jul 27, 2011

      Not yet. But this is coming soon.

  2. Jul 26, 2011

    Anonymous

    Operator + denotes iteration (one or one)

    Must be: one or more

    1. Jul 27, 2011

      Thanks

  3. Jul 28, 2011

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

  4. Jul 29, 2011

    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. Jul 30, 2011

      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. Jul 30, 2011

        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. Jul 30, 2011

    typeRHS should be prefixUnaryExpression (typeOperation prefixUnaryExpression)*

    postfixUnaryOperation should be memberAccessOperation postfixUnaryExpression

    1. Aug 02, 2011

      Thanks

      1. Aug 02, 2011

        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. Aug 03, 2011

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

  6. Aug 03, 2011

    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:

    1. Aug 04, 2011

      Fixed. Thanks

  7. Aug 04, 2011

    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. Aug 04, 2011

      Fixed. Thanks

    2. Aug 04, 2011

      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. Oct 08, 2011

    Possible this is a mistake in the Precedence table:

    Equality operators: ==!=====!===

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

    1. Oct 09, 2011

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

  9. Feb 27, 2014

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

    1. Feb 28, 2014

      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. Jul 15, 2014

    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. Jul 23, 2014

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