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

Grammar railroad diagram #337

Open
mingodad opened this issue Oct 23, 2024 · 1 comment
Open

Grammar railroad diagram #337

mingodad opened this issue Oct 23, 2024 · 1 comment
Labels
Enhancement New feature or request

Comments

@mingodad
Copy link

Location

https://github.com/swiftlang/swift-book/blob/main/TSPL.docc/ReferenceManual/SummaryOfTheGrammar.md

Description

Using an EBNF understood by https://github.com/GuntherRademacher/rr we can have a nice navigable railroad diagram (see a manual conversion that already works, although still need some work on it).

//
// EBNF to be viewd at
//    (IPV6) https://www.bottlecaps.de/rr/ui
//    (IPV4) https://rr.red-dove.com/ui
//
// Copy and paste this at one of the urls shown above in the 'Edit Grammar' tab
// then click the 'View Diagram' tab.
//

//Summary of the Grammar

//Lexical Structure
//Grammar of whitespace

whitespace ::= whitespace-item whitespace?
whitespace-item ::= line-break
whitespace-item ::= inline-space
whitespace-item ::= comment
whitespace-item ::= multiline-comment
///whitespace-item ::= U+0000, U+000B, or U+000C

///line-break ::= U+000A
///line-break ::= U+000D
///line-break ::= U+000D followed by U+000A

inline-spaces ::= inline-space inline-spaces?
///inline-space ::= U+0009 or U+0020

comment ::= "//" comment-text line-break
multiline-comment ::= "/*" multiline-comment-text "*/"

comment-text ::= comment-text-item comment-text?
///comment-text-item ::= Any Unicode scalar value except U+000A or U+000D

multiline-comment-text ::= multiline-comment-text-item multiline-comment-text?
multiline-comment-text-item ::= multiline-comment
multiline-comment-text-item ::= comment-text-item
///multiline-comment-text-item ::= Any Unicode scalar value except /* or */

//Grammar of an identifier

identifier ::= identifier-head identifier-characters?
identifier ::= '`' identifier-head identifier-characters? '`'
identifier ::= implicit-parameter-name
identifier ::= property-wrapper-projection
identifier-list ::= identifier | identifier ',' identifier-list

///identifier-head ::= Upper- or lowercase letter A through Z
identifier-head ::= '_'
///identifier-head ::= U+00A8, U+00AA, U+00AD, U+00AF, U+00B2–U+00B5, or U+00B7–U+00BA
///identifier-head ::= U+00BC–U+00BE, U+00C0–U+00D6, U+00D8–U+00F6, or U+00F8–U+00FF
///identifier-head ::= U+0100–U+02FF, U+0370–U+167F, U+1681–U+180D, or U+180F–U+1DBF
///identifier-head ::= U+1E00–U+1FFF
///identifier-head ::= U+200B–U+200D, U+202A–U+202E, U+203F–U+2040, U+2054, or U+2060–U+206F
///identifier-head ::= U+2070–U+20CF, U+2100–U+218F, U+2460–U+24FF, or U+2776–U+2793
///identifier-head ::= U+2C00–U+2DFF or U+2E80–U+2FFF
///identifier-head ::= U+3004–U+3007, U+3021–U+302F, U+3031–U+303F, or U+3040–U+D7FF
///identifier-head ::= U+F900–U+FD3D, U+FD40–U+FDCF, U+FDF0–U+FE1F, or U+FE30–U+FE44
///identifier-head ::= U+FE47–U+FFFD
///identifier-head ::= U+10000–U+1FFFD, U+20000–U+2FFFD, U+30000–U+3FFFD, or U+40000–U+4FFFD
///identifier-head ::= U+50000–U+5FFFD, U+60000–U+6FFFD, U+70000–U+7FFFD, or U+80000–U+8FFFD
///identifier-head ::= U+90000–U+9FFFD, U+A0000–U+AFFFD, U+B0000–U+BFFFD, or U+C0000–U+CFFFD
///identifier-head ::= U+D0000–U+DFFFD or U+E0000–U+EFFFD

identifier-character ::= [0-9]
///identifier-character ::= U+0300–U+036F, U+1DC0–U+1DFF, U+20D0–U+20FF, or U+FE20–U+FE2F
identifier-character ::= identifier-head
identifier-characters ::= identifier-character identifier-characters?

implicit-parameter-name ::= '$' decimal-digits
property-wrapper-projection ::= '$' identifier-characters

//Grammar of a literal

literal ::= numeric-literal | string-literal | regular-expression-literal | boolean-literal | nil-literal

numeric-literal ::= '-'? integer-literal | '-'? floating-point-literal
boolean-literal ::= "true" | "false"
nil-literal ::= "nil"

//Grammar of an integer literal

integer-literal ::= binary-literal
integer-literal ::= octal-literal
integer-literal ::= decimal-literal
integer-literal ::= hexadecimal-literal

binary-literal ::= "0b" binary-digit binary-literal-characters?
binary-digit ::= [01]
binary-literal-character ::= binary-digit | '_'
binary-literal-characters ::= binary-literal-character binary-literal-characters?

octal-literal ::= "0o" octal-digit octal-literal-characters?
octal-digit ::= [0-7]
octal-literal-character ::= octal-digit | '_'
octal-literal-characters ::= octal-literal-character octal-literal-characters?

decimal-literal ::= decimal-digit decimal-literal-characters?
decimal-digit ::= [0-9]
decimal-digits ::= decimal-digit decimal-digits?
decimal-literal-character ::= decimal-digit | '_'
decimal-literal-characters ::= decimal-literal-character decimal-literal-characters?

hexadecimal-literal ::= "0x" hexadecimal-digit hexadecimal-literal-characters?
hexadecimal-digit ::= [0-9a-fA-F]
hexadecimal-literal-character ::= hexadecimal-digit | '_'
hexadecimal-literal-characters ::= hexadecimal-literal-character hexadecimal-literal-characters?

//Grammar of a floating-point literal

floating-point-literal ::= decimal-literal decimal-fraction? decimal-exponent?
floating-point-literal ::= hexadecimal-literal hexadecimal-fraction? hexadecimal-exponent

decimal-fraction ::= '.' decimal-literal
decimal-exponent ::= floating-point-e sign? decimal-literal

hexadecimal-fraction ::= '.' hexadecimal-digit hexadecimal-literal-characters?
hexadecimal-exponent ::= floating-point-p sign? decimal-literal

floating-point-e ::= [eE]
floating-point-p ::= [pP]
sign ::= [+-]

//Grammar of a string literal

string-literal ::= static-string-literal | interpolated-string-literal

string-literal-opening-delimiter ::= extended-string-literal-delimiter? '"'
string-literal-closing-delimiter ::= '"' extended-string-literal-delimiter?

static-string-literal ::= string-literal-opening-delimiter quoted-text? string-literal-closing-delimiter
static-string-literal ::= multiline-string-literal-opening-delimiter multiline-quoted-text? multiline-string-literal-closing-delimiter

multiline-string-literal-opening-delimiter ::= extended-string-literal-delimiter? '"""'
multiline-string-literal-closing-delimiter ::= '"""' extended-string-literal-delimiter?
extended-string-literal-delimiter ::= '#' extended-string-literal-delimiter?

quoted-text ::= quoted-text-item quoted-text?
quoted-text-item ::= escaped-character
///quoted-text-item ::= Any Unicode scalar value except ", \, U+000A, or U+000D

multiline-quoted-text ::= multiline-quoted-text-item multiline-quoted-text?
multiline-quoted-text-item ::= escaped-character
///multiline-quoted-text-item ::= Any Unicode scalar value except \
multiline-quoted-text-item ::= escaped-newline

interpolated-string-literal ::= string-literal-opening-delimiter interpolated-text? string-literal-closing-delimiter
interpolated-string-literal ::= multiline-string-literal-opening-delimiter multiline-interpolated-text? multiline-string-literal-closing-delimiter

interpolated-text ::= interpolated-text-item interpolated-text?
interpolated-text-item ::= '(' expression ')' | quoted-text-item

multiline-interpolated-text ::= multiline-interpolated-text-item multiline-interpolated-text?
multiline-interpolated-text-item ::= '(' expression ')' | multiline-quoted-text-item

escape-sequence ::= '\' extended-string-literal-delimiter
escaped-character ::= escape-sequence '0' | escape-sequence '\' | escape-sequence 't' | escape-sequence 'n' | escape-sequence 'r' | escape-sequence '"' | escape-sequence "'"
escaped-character ::= escape-sequence "u{" unicode-scalar-digits '}'
unicode-scalar-digits ::= Between one and eight hexadecimal digits

escaped-newline ::= escape-sequence inline-spaces? line-break

//Grammar of a regular expression literal

regular-expression-literal ::= regular-expression-literal-opening-delimiter regular-expression regular-expression-literal-closing-delimiter
regular-expression ::= Any regular expression

regular-expression-literal-opening-delimiter ::= extended-regular-expression-literal-delimiter? '/'
regular-expression-literal-closing-delimiter ::= '/' extended-regular-expression-literal-delimiter?

extended-regular-expression-literal-delimiter ::= '#' extended-regular-expression-literal-delimiter?

//Grammar of operators

operator ::= operator-head operator-characters?
operator ::= dot-operator-head dot-operator-characters

operator-head ::= '/' | '=' | '-' | '+' | '!' | '*' | '%' | '<' | '>' | '&' | '|' | '^' | '~' | '?'
///operator-head ::= U+00A1–U+00A7
///operator-head ::= U+00A9 or U+00AB
///operator-head ::= U+00AC or U+00AE
///operator-head ::= U+00B0–U+00B1
///operator-head ::= U+00B6, U+00BB, U+00BF, U+00D7, or U+00F7
///operator-head ::= U+2016–U+2017
///operator-head ::= U+2020–U+2027
///operator-head ::= U+2030–U+203E
///operator-head ::= U+2041–U+2053
///operator-head ::= U+2055–U+205E
///operator-head ::= U+2190–U+23FF
///operator-head ::= U+2500–U+2775
///operator-head ::= U+2794–U+2BFF
///operator-head ::= U+2E00–U+2E7F
///operator-head ::= U+3001–U+3003
///operator-head ::= U+3008–U+3020
///operator-head ::= U+3030

operator-character ::= operator-head
///operator-character ::= U+0300–U+036F
///operator-character ::= U+1DC0–U+1DFF
///operator-character ::= U+20D0–U+20FF
///operator-character ::= U+FE00–U+FE0F
///operator-character ::= U+FE20–U+FE2F
///operator-character ::= U+E0100–U+E01EF
operator-characters ::= operator-character operator-characters?

dot-operator-head ::= '.'
dot-operator-character ::= '.' | operator-character
dot-operator-characters ::= dot-operator-character dot-operator-characters?

infix-operator ::= operator
prefix-operator ::= operator
postfix-operator ::= operator

//Types
//Grammar of a type

type ::= function-type
type ::= array-type
type ::= dictionary-type
type ::= type-identifier
type ::= tuple-type
type ::= optional-type
type ::= implicitly-unwrapped-optional-type
type ::= protocol-composition-type
type ::= opaque-type
type ::= metatype-type
type ::= any-type
type ::= self-type
type ::= '(' type ')'

//Grammar of a type annotation

type-annotation ::= ':' attributes? "inout"? type

//Grammar of a type identifier

type-identifier ::= type-name generic-argument-clause? | type-name generic-argument-clause? '.' type-identifier
type-name ::= identifier

//Grammar of a tuple type

tuple-type ::= '(' ')' | '(' tuple-type-element ',' tuple-type-element-list ')'
tuple-type-element-list ::= tuple-type-element | tuple-type-element ',' tuple-type-element-list
tuple-type-element ::= element-name type-annotation | type
element-name ::= identifier

//Grammar of a function type

function-type ::= attributes? function-type-argument-clause "async"? throws-clause? "->" type

function-type-argument-clause ::= '(' ')'
function-type-argument-clause ::= '(' function-type-argument-list "..."? ')'

function-type-argument-list ::= function-type-argument | function-type-argument ',' function-type-argument-list
function-type-argument ::= attributes? "inout"? type | argument-label type-annotation
argument-label ::= identifier

throws-clause ::= "throws" | "throws" '(' type ')'

//Grammar of an array type

array-type ::= '[' type ']'

//Grammar of a dictionary type

dictionary-type ::= '[' type ':' type ']'

//Grammar of an optional type

optional-type ::= type ?

//Grammar of an implicitly unwrapped optional type

implicitly-unwrapped-optional-type ::= type '!'

//Grammar of a protocol composition type

protocol-composition-type ::= type-identifier '&' protocol-composition-continuation
protocol-composition-continuation ::= type-identifier | protocol-composition-type

//Grammar of an opaque type

opaque-type ::= "some" type

//Grammar of a boxed protocol type

boxed-protocol-type ::= "any" type

//Grammar of a metatype type

metatype-type ::= type '.' "Type" | type '.' "Protocol"

//Grammar of an Any type

any-type ::= "Any"

//Grammar of a Self type

self-type ::= "Self"

//Grammar of a type inheritance clause

type-inheritance-clause ::= ':' type-inheritance-list
type-inheritance-list ::= attributes? type-identifier | attributes? type-identifier ',' type-inheritance-list

//Expressions
//Grammar of an expression

expression ::= try-operator? await-operator? prefix-expression infix-expressions? '\'

//Grammar of a prefix expression

prefix-expression ::= prefix-operator? postfix-expression
prefix-expression ::= in-out-expression

//Grammar of an in-out expression

in-out-expression ::= '&' primary-expression

//Grammar of a try expression

try-operator ::= "try" | "try" '?' | "try" '!'

//Grammar of an await expression

await-operator ::= "await"

//Grammar of an infix expression

infix-expression ::= infix-operator prefix-expression
infix-expression ::= assignment-operator try-operator? await-operator? prefix-expression
infix-expression ::= conditional-operator try-operator? await-operator? prefix-expression
infix-expression ::= type-casting-operator
infix-expressions ::= infix-expression infix-expressions?

//Grammar of an assignment operator

assignment-operator ::= '='

//Grammar of a conditional operator

conditional-operator ::= '?' expression ':'

//Grammar of a type-casting operator

type-casting-operator ::= 'is' type
type-casting-operator ::= 'as' type
type-casting-operator ::= 'as' '?' type
type-casting-operator ::= 'as' '!' type

//Grammar of a primary expression

primary-expression ::= identifier generic-argument-clause?
primary-expression ::= literal-expression
primary-expression ::= self-expression
primary-expression ::= superclass-expression
primary-expression ::= conditional-expression
primary-expression ::= closure-expression
primary-expression ::= parenthesized-expression
primary-expression ::= tuple-expression
primary-expression ::= implicit-member-expression
primary-expression ::= wildcard-expression
primary-expression ::= macro-expansion-expression
primary-expression ::= key-path-expression
primary-expression ::= selector-expression
primary-expression ::= key-path-string-expression

//Grammar of a literal expression

literal-expression ::= literal
literal-expression ::= array-literal | dictionary-literal | playground-literal

array-literal ::= '[' array-literal-items? ']'
array-literal-items ::= array-literal-item ','? | array-literal-item ',' array-literal-items
array-literal-item ::= expression

dictionary-literal ::= '[' dictionary-literal-items ']' | '[' ':' ']'
dictionary-literal-items ::= dictionary-literal-item ','? | dictionary-literal-item ',' dictionary-literal-items
dictionary-literal-item ::= expression ':' expression

playground-literal ::= "#colorLiteral" '(' "red" ':' expression ',' "green" ':' expression ',' "blue" ':' expression ',' "alpha" ':' expression ')'
playground-literal ::= "#fileLiteral" '(' "resourceName" ':' expression ')'
playground-literal ::= "#imageLiteral" '(' "resourceName" ':' expression ')'

//Grammar of a self expression

self-expression ::= "self" | self-method-expression | self-subscript-expression | self-initializer-expression

self-method-expression ::= "self" '.' identifier
self-subscript-expression ::= "self" '[' function-call-argument-list ']'
self-initializer-expression ::= "self" '.' "init"

//Grammar of a superclass expression

superclass-expression ::= superclass-method-expression | superclass-subscript-expression | superclass-initializer-expression

superclass-method-expression ::= "super" '.' identifier
superclass-subscript-expression ::= "super" '[' function-call-argument-list ']'
superclass-initializer-expression ::= "super" '.' "init"

//Grammar of a conditional expression

conditional-expression ::= if-expression | switch-expression

if-expression ::= "if" condition-list '{' statement '}' if-expression-tail
if-expression-tail ::= "else" if-expression
if-expression-tail ::= "else" '{' statement '}'

switch-expression ::= "switch" expression '{' switch-expression-cases '}'
switch-expression-cases ::= switch-expression-case switch-expression-cases?
switch-expression-case ::= case-label statement
switch-expression-case ::= default-label statement

//Grammar of a closure expression

closure-expression ::= '{' attributes? closure-signature? statements? '}'

closure-signature ::= capture-list? closure-parameter-clause "async"? throws-clause? function-result? "in"
closure-signature ::= capture-list "in"

closure-parameter-clause ::= '(' ')' | '(' closure-parameter-list ')' | identifier-list
closure-parameter-list ::= closure-parameter | closure-parameter ',' closure-parameter-list
closure-parameter ::= closure-parameter-name type-annotation?
closure-parameter ::= closure-parameter-name type-annotation "..."
closure-parameter-name ::= identifier

capture-list ::= '[' capture-list-items ']'
capture-list-items ::= capture-list-item | capture-list-item ',' capture-list-items
capture-list-item ::= capture-specifier? identifier
capture-list-item ::= capture-specifier? identifier '=' expression
capture-list-item ::= capture-specifier? self-expression
capture-specifier ::= "weak" | "unowned" | "unowned(safe)" | "unowned(unsafe)"

//Grammar of an implicit member expression

implicit-member-expression ::= '.' identifier
implicit-member-expression ::= '.' identifier '.' postfix-expression

//Grammar of a parenthesized expression

parenthesized-expression ::= '(' expression ')'

//Grammar of a tuple expression

tuple-expression ::= '(' ')' | '(' tuple-element ',' tuple-element-list ')'
tuple-element-list ::= tuple-element | tuple-element ',' tuple-element-list
tuple-element ::= expression | identifier ':' expression

//Grammar of a wildcard expression

wildcard-expression ::= '_'

//Grammar of a macro-expansion expression

macro-expansion-expression ::= '#' identifier generic-argument-clause? function-call-argument-clause? trailing-closures?

//Grammar of a key-path expression

key-path-expression ::= '\' type? '.' key-path-components
key-path-components ::= key-path-component | key-path-component '.' key-path-components
key-path-component ::= identifier key-path-postfixes? | key-path-postfixes

key-path-postfixes ::= key-path-postfix key-path-postfixes?
key-path-postfix ::= '?' | '!' | "self" | '[' function-call-argument-list ']'

//Grammar of a selector expression

selector-expression ::= "#selector" '(' expression ')'
selector-expression ::= "#selector" '(' "getter:" expression ')'
selector-expression ::= "#selector" '(' "setter:" expression ')'

//Grammar of a key-path string expression

key-path-string-expression ::= "#keyPath" '(' expression ')'

//Grammar of a postfix expression

postfix-expression ::= primary-expression
postfix-expression ::= postfix-expression postfix-operator
postfix-expression ::= function-call-expression
postfix-expression ::= initializer-expression
postfix-expression ::= explicit-member-expression
postfix-expression ::= postfix-self-expression
postfix-expression ::= subscript-expression
postfix-expression ::= forced-value-expression
postfix-expression ::= optional-chaining-expression

//Grammar of a function call expression

function-call-expression ::= postfix-expression function-call-argument-clause
function-call-expression ::= postfix-expression function-call-argument-clause? trailing-closures

function-call-argument-clause ::= '(' ')' | '(' function-call-argument-list ')'
function-call-argument-list ::= function-call-argument | function-call-argument ',' function-call-argument-list
function-call-argument ::= expression | identifier ':' expression
function-call-argument ::= operator | identifier ':' operator

trailing-closures ::= closure-expression labeled-trailing-closures?
labeled-trailing-closures ::= labeled-trailing-closure labeled-trailing-closures?
labeled-trailing-closure ::= identifier ':' closure-expression

//Grammar of an initializer expression

initializer-expression ::= postfix-expression '.' "init"
initializer-expression ::= postfix-expression '.' "init" '(' argument-names ')'

//Grammar of an explicit member expression

explicit-member-expression ::= postfix-expression '.' decimal-digits
explicit-member-expression ::= postfix-expression '.' identifier generic-argument-clause?
explicit-member-expression ::= postfix-expression '.' identifier '(' argument-names ')'
explicit-member-expression ::= postfix-expression conditional-compilation-block

argument-names ::= argument-name argument-names?
argument-name ::= identifier ':'

//Grammar of a postfix self expression

postfix-self-expression ::= postfix-expression '.' "self"

//Grammar of a subscript expression

subscript-expression ::= postfix-expression '[' function-call-argument-list ']'

//Grammar of a forced-value expression

forced-value-expression ::= postfix-expression '!'

//Grammar of an optional-chaining expression

optional-chaining-expression ::= postfix-expression '?'

//Statements
//Grammar of a statement

statement ::= expression ';'?
statement ::= declaration ';'?
statement ::= loop-statement ';'?
statement ::= branch-statement ';'?
statement ::= labeled-statement ';'?
statement ::= control-transfer-statement ';'?
statement ::= defer-statement ';'?
statement ::= do-statement ';'?
statement ::= compiler-control-statement
statements ::= statement statements?

//Grammar of a loop statement

loop-statement ::= for-in-statement
loop-statement ::= while-statement
loop-statement ::= repeat-while-statement

//Grammar of a for-in statement

for-in-statement ::= "for" "case"? pattern "in" expression where-clause? code-block

//Grammar of a while statement

while-statement ::= "while" condition-list code-block

condition-list ::= condition | condition ',' condition-list
condition ::= expression | availability-condition | case-condition | optional-binding-condition

case-condition ::= "case" pattern initializer
optional-binding-condition ::= "let" pattern initializer? | "var" pattern initializer?

//Grammar of a repeat-while statement

repeat-while-statement ::= "repeat" code-block "while" expression

//Grammar of a branch statement

branch-statement ::= if-statement
branch-statement ::= guard-statement
branch-statement ::= switch-statement

//Grammar of an if statement

if-statement ::= "if" condition-list code-block else-clause?
else-clause ::= "else" code-block | "else" if-statement

//Grammar of a guard statement

guard-statement ::= "guard" condition-list "else" code-block

//Grammar of a switch statement

switch-statement ::= "switch" expression '{' switch-cases? '}'
switch-cases ::= switch-case switch-cases?
switch-case ::= case-label statements
switch-case ::= default-label statements
switch-case ::= conditional-switch-case

case-label ::= attributes? "case" case-item-list ':'
case-item-list ::= pattern where-clause? | pattern where-clause? ',' case-item-list
default-label ::= attributes? "default" ':'

where-clause ::= "where" where-expression
where-expression ::= expression

conditional-switch-case ::= switch-if-directive-clause switch-elseif-directive-clauses? switch-else-directive-clause? endif-directive
switch-if-directive-clause ::= if-directive compilation-condition switch-cases?
switch-elseif-directive-clauses ::= elseif-directive-clause switch-elseif-directive-clauses?
switch-elseif-directive-clause ::= elseif-directive compilation-condition switch-cases?
switch-else-directive-clause ::= else-directive switch-cases?

//Grammar of a labeled statement

labeled-statement ::= statement-label loop-statement
labeled-statement ::= statement-label if-statement
labeled-statement ::= statement-label switch-statement
labeled-statement ::= statement-label do-statement

statement-label ::= label-name ':'
label-name ::= identifier

//Grammar of a control transfer statement

control-transfer-statement ::= break-statement
control-transfer-statement ::= continue-statement
control-transfer-statement ::= fallthrough-statement
control-transfer-statement ::= return-statement
control-transfer-statement ::= throw-statement

//Grammar of a break statement

break-statement ::= "break" label-name?

//Grammar of a continue statement

continue-statement ::= "continue" label-name?

//Grammar of a fallthrough statement

fallthrough-statement ::= "fallthrough"

//Grammar of a return statement

return-statement ::= "return" expression?

//Grammar of a throw statement

throw-statement ::= "throw" expression

//Grammar of a defer statement

defer-statement ::= "defer" code-block

//Grammar of a do statement

do-statement ::= "do" throws-clause? code-block catch-clauses?
catch-clauses ::= catch-clause catch-clauses?
catch-clause ::= "catch" catch-pattern-list? code-block
catch-pattern-list ::= catch-pattern | catch-pattern ',' catch-pattern-list
catch-pattern ::= pattern where-clause?

//Grammar of a compiler control statement

compiler-control-statement ::= conditional-compilation-block
compiler-control-statement ::= line-control-statement
compiler-control-statement ::= diagnostic-statement

//Grammar of a conditional compilation block

conditional-compilation-block ::= if-directive-clause elseif-directive-clauses? else-directive-clause? endif-directive

if-directive-clause ::= if-directive compilation-condition statements?
elseif-directive-clauses ::= elseif-directive-clause elseif-directive-clauses?
elseif-directive-clause ::= elseif-directive compilation-condition statements?
else-directive-clause ::= else-directive statements?
if-directive ::= "#if"
elseif-directive ::= "#elseif"
else-directive ::= "#else"
endif-directive ::= "#endif"

compilation-condition ::= platform-condition
compilation-condition ::= identifier
compilation-condition ::= boolean-literal
compilation-condition ::= '(' compilation-condition ')'
compilation-condition ::= '!' compilation-condition
compilation-condition ::= compilation-condition "&&" compilation-condition
compilation-condition ::= compilation-condition "||" compilation-condition

platform-condition ::= "os" '(' operating-system ')'
platform-condition ::= "arch" '(' architecture ')'
platform-condition ::= "swift" '(' ">=" swift-version ')' | "swift" '(' '<' swift-version ')'
platform-condition ::= "compiler" '(' ">=" swift-version ')' | "compiler" '(' '<' swift-version ')'
platform-condition ::= "canImport" '(' import-path ')'
platform-condition ::= "targetEnvironment" '(' environment ')'

operating-system ::= "macOS" | "iOS" | "watchOS" | "tvOS" | "visionOS" | "Linux" | "Windows"
architecture ::= "i386" | "x86_64" | "arm" | "arm64"
swift-version ::= decimal-digits swift-version-continuation?
swift-version-continuation ::= '.' decimal-digits swift-version-continuation?
environment ::= "simulator" | "macCatalyst"

//Grammar of a line control statement

line-control-statement ::= "#sourceLocation" '(' "file:" file-path ',' "line:" line-number ')'
line-control-statement ::= "#sourceLocation" '(' ')'
///line-number ::= A decimal integer greater than zero
file-path ::= static-string-literal

//Grammar of an availability condition

availability-condition ::= "#available" '(' availability-arguments ')'
availability-condition ::= "#unavailable" '(' availability-arguments ')'
availability-arguments ::= availability-argument | availability-argument ',' availability-arguments
availability-argument ::= platform-name platform-version
availability-argument ::= '*'

platform-name ::= "iOS" | "iOSApplicationExtension"
platform-name ::= "macOS" | "macOSApplicationExtension"
platform-name ::= "macCatalyst" | "macCatalystApplicationExtension"
platform-name ::= "watchOS" | "watchOSApplicationExtension"
platform-name ::= "tvOS" | "tvOSApplicationExtension"
platform-name ::= "visionOS" | "visionOSApplicationExtension"
platform-version ::= decimal-digits
platform-version ::= decimal-digits '.' decimal-digits
platform-version ::= decimal-digits '.' decimal-digits '.' decimal-digits

//Declarations
//Grammar of a declaration

declaration ::= import-declaration
declaration ::= constant-declaration
declaration ::= variable-declaration
declaration ::= typealias-declaration
declaration ::= function-declaration
declaration ::= enum-declaration
declaration ::= struct-declaration
declaration ::= class-declaration
declaration ::= actor-declaration
declaration ::= protocol-declaration
declaration ::= initializer-declaration
declaration ::= deinitializer-declaration
declaration ::= extension-declaration
declaration ::= subscript-declaration
declaration ::= operator-declaration
declaration ::= precedence-group-declaration '\'

//Grammar of a top-level declaration

top-level-declaration ::= statements?

//Grammar of a code block

code-block ::= '{' statements? '}'

//Grammar of an import declaration

import-declaration ::= attributes? "import" import-kind? import-path

import-kind ::= "typealias" | "struct" | "class" | "enum" | "protocol" | "let" | "var" | "func"
import-path ::= identifier | identifier '.' import-path

//Grammar of a constant declaration

constant-declaration ::= attributes? declaration-modifiers? "let" pattern-initializer-list

pattern-initializer-list ::= pattern-initializer | pattern-initializer ',' pattern-initializer-list
pattern-initializer ::= pattern initializer?
initializer ::= '=' expression

//Grammar of a variable declaration

variable-declaration ::= variable-declaration-head pattern-initializer-list
variable-declaration ::= variable-declaration-head variable-name type-annotation code-block
variable-declaration ::= variable-declaration-head variable-name type-annotation getter-setter-block
variable-declaration ::= variable-declaration-head variable-name type-annotation getter-setter-keyword-block
variable-declaration ::= variable-declaration-head variable-name initializer willSet-didSet-block
variable-declaration ::= variable-declaration-head variable-name type-annotation initializer? willSet-didSet-block

variable-declaration-head ::= attributes? declaration-modifiers? "var"
variable-name ::= identifier

getter-setter-block ::= code-block
getter-setter-block ::= '{' getter-clause setter-clause? '}'
getter-setter-block ::= '{' setter-clause getter-clause '}'
getter-clause ::= attributes? mutation-modifier? "get" code-block
setter-clause ::= attributes? mutation-modifier? "set" setter-name? code-block
setter-name ::= '(' identifier ')'

getter-setter-keyword-block ::= '{' getter-keyword-clause setter-keyword-clause? '}'
getter-setter-keyword-block ::= '{' setter-keyword-clause getter-keyword-clause '}'
getter-keyword-clause ::= attributes? mutation-modifier? "get"
setter-keyword-clause ::= attributes? mutation-modifier? "set"

willSet-didSet-block ::= '{' willSet-clause didSet-clause? '}'
willSet-didSet-block ::= '{' didSet-clause willSet-clause? '}'
willSet-clause ::= attributes? "willSet" setter-name? code-block
didSet-clause ::= attributes? "didSet" setter-name? code-block

//Grammar of a type alias declaration

typealias-declaration ::= attributes? access-level-modifier? "typealias" typealias-name generic-parameter-clause? typealias-assignment
typealias-name ::= identifier
typealias-assignment ::= '=' type

//Grammar of a function declaration

function-declaration ::= function-head function-name generic-parameter-clause? function-signature generic-where-clause? function-body?

function-head ::= attributes? declaration-modifiers? "func"
function-name ::= identifier | operator

function-signature ::= parameter-clause "async"? throws-clause? function-result?
function-signature ::= parameter-clause "async"? "rethrows" function-result?
function-result ::= "->" attributes? type
function-body ::= code-block

parameter-clause ::= '(' ')' | '(' parameter-list ')'
parameter-list ::= parameter | parameter ',' parameter-list
parameter ::= external-parameter-name? local-parameter-name parameter-type-annotation default-argument-clause?
parameter ::= external-parameter-name? local-parameter-name parameter-type-annotation
parameter ::= external-parameter-name? local-parameter-name parameter-type-annotation "..."

external-parameter-name ::= identifier
local-parameter-name ::= identifier
parameter-type-annotation ::= ':' attributes? parameter-modifier? type
parameter-modifier ::= "inout" | "borrowing" | "consuming"
default-argument-clause ::= '=' expression

//Grammar of an enumeration declaration

enum-declaration ::= attributes? access-level-modifier? union-style-enum
enum-declaration ::= attributes? access-level-modifier? raw-value-style-enum

union-style-enum ::= "indirect"? "enum" enum-name generic-parameter-clause? type-inheritance-clause? generic-where-clause? '{' union-style-enum-members? '}'
union-style-enum-members ::= union-style-enum-member union-style-enum-members?
union-style-enum-member ::= declaration | union-style-enum-case-clause | compiler-control-statement
union-style-enum-case-clause ::= attributes? "indirect"? "case" union-style-enum-case-list
union-style-enum-case-list ::= union-style-enum-case | union-style-enum-case ',' union-style-enum-case-list
union-style-enum-case ::= enum-case-name tuple-type?
enum-name ::= identifier
enum-case-name ::= identifier

raw-value-style-enum ::= "enum" enum-name generic-parameter-clause? type-inheritance-clause generic-where-clause? '{' raw-value-style-enum-members '}'
raw-value-style-enum-members ::= raw-value-style-enum-member raw-value-style-enum-members?
raw-value-style-enum-member ::= declaration | raw-value-style-enum-case-clause | compiler-control-statement
raw-value-style-enum-case-clause ::= attributes? "case" raw-value-style-enum-case-list
raw-value-style-enum-case-list ::= raw-value-style-enum-case | raw-value-style-enum-case ',' raw-value-style-enum-case-list
raw-value-style-enum-case ::= enum-case-name raw-value-assignment?
raw-value-assignment ::= '=' raw-value-literal
raw-value-literal ::= numeric-literal | static-string-literal | boolean-literal

//Grammar of a structure declaration

struct-declaration ::= attributes? access-level-modifier? "struct" struct-name generic-parameter-clause? type-inheritance-clause? generic-where-clause? struct-body
struct-name ::= identifier
struct-body ::= '{' struct-members? '}'

struct-members ::= struct-member struct-members?
struct-member ::= declaration | compiler-control-statement

//Grammar of a class declaration

class-declaration ::= attributes? access-level-modifier? "final"? "class" class-name generic-parameter-clause? type-inheritance-clause? generic-where-clause? class-body
class-declaration ::= attributes? "final" access-level-modifier? "class" class-name generic-parameter-clause? type-inheritance-clause? generic-where-clause? class-body
class-name ::= identifier
class-body ::= '{' class-members? '}'

class-members ::= class-member class-members?
class-member ::= declaration | compiler-control-statement

//Grammar of an actor declaration

actor-declaration ::= attributes? access-level-modifier? "actor" actor-name generic-parameter-clause? type-inheritance-clause? generic-where-clause? actor-body
actor-name ::= identifier
actor-body ::= '{' actor-members? '}'

actor-members ::= actor-member actor-members?
actor-member ::= declaration | compiler-control-statement

//Grammar of a protocol declaration

protocol-declaration ::= attributes? access-level-modifier? "protocol" protocol-name type-inheritance-clause? generic-where-clause? protocol-body
protocol-name ::= identifier
protocol-body ::= '{' protocol-members? '}'

protocol-members ::= protocol-member protocol-members?
protocol-member ::= protocol-member-declaration | compiler-control-statement

protocol-member-declaration ::= protocol-property-declaration
protocol-member-declaration ::= protocol-method-declaration
protocol-member-declaration ::= protocol-initializer-declaration
protocol-member-declaration ::= protocol-subscript-declaration
protocol-member-declaration ::= protocol-associated-type-declaration
protocol-member-declaration ::= typealias-declaration

//Grammar of a protocol property declaration

protocol-property-declaration ::= variable-declaration-head variable-name type-annotation getter-setter-keyword-block

//Grammar of a protocol method declaration

protocol-method-declaration ::= function-head function-name generic-parameter-clause? function-signature generic-where-clause?

//Grammar of a protocol initializer declaration

protocol-initializer-declaration ::= initializer-head generic-parameter-clause? parameter-clause throws-clause? generic-where-clause?
protocol-initializer-declaration ::= initializer-head generic-parameter-clause? parameter-clause "rethrows" generic-where-clause?

//Grammar of a protocol subscript declaration

protocol-subscript-declaration ::= subscript-head subscript-result generic-where-clause? getter-setter-keyword-block

//Grammar of a protocol associated type declaration

protocol-associated-type-declaration ::= attributes? access-level-modifier? associatedtype typealias-name type-inheritance-clause? typealias-assignment? generic-where-clause?

//Grammar of an initializer declaration

initializer-declaration ::= initializer-head generic-parameter-clause? parameter-clause "async"? throws-clause? generic-where-clause? initializer-body
initializer-declaration ::= initializer-head generic-parameter-clause? parameter-clause "async"? "rethrows" generic-where-clause? initializer-body
initializer-head ::= attributes? declaration-modifiers? "init"
initializer-head ::= attributes? declaration-modifiers? "init" '?'
initializer-head ::= attributes? declaration-modifiers? "init" '!'
initializer-body ::= code-block

//Grammar of a deinitializer declaration

deinitializer-declaration ::= attributes? "deinit" code-block

//Grammar of an extension declaration

extension-declaration ::= attributes? access-level-modifier? "extension" type-identifier type-inheritance-clause? generic-where-clause? extension-body
extension-body ::= '{' extension-members? '}'

extension-members ::= extension-member extension-members?
extension-member ::= declaration | compiler-control-statement

//Grammar of a subscript declaration

subscript-declaration ::= subscript-head subscript-result generic-where-clause? code-block
subscript-declaration ::= subscript-head subscript-result generic-where-clause? getter-setter-block
subscript-declaration ::= subscript-head subscript-result generic-where-clause? getter-setter-keyword-block
subscript-head ::= attributes? declaration-modifiers? "subscript" generic-parameter-clause? parameter-clause
subscript-result ::= "->" attributes? type

//Grammar of a macro declaration

macro-declaration ::= macro-head identifier generic-parameter-clause? macro-signature macro-definition? generic-where-clause
macro-head ::= attributes? declaration-modifiers? "macro"
macro-signature ::= parameter-clause macro-function-signature-result?
macro-function-signature-result ::= "->" type
macro-definition ::= '=' expression

//Grammar of an operator declaration

operator-declaration ::= prefix-operator-declaration | postfix-operator-declaration | infix-operator-declaration

prefix-operator-declaration ::= "prefix" operator operator
postfix-operator-declaration ::= "postfix" operator operator
infix-operator-declaration ::= "infix" operator operator infix-operator-group?

infix-operator-group ::= ':' precedence-group-name

//Grammar of a precedence group declaration

precedence-group-declaration ::= precedencegroup precedence-group-name '{' precedence-group-attributes? '}'

precedence-group-attributes ::= precedence-group-attribute precedence-group-attributes?
precedence-group-attribute ::= precedence-group-relation
precedence-group-attribute ::= precedence-group-assignment
precedence-group-attribute ::= precedence-group-associativity

precedence-group-relation ::= "higherThan" ':' precedence-group-names
precedence-group-relation ::= "lowerThan" ':' precedence-group-names

precedence-group-assignment ::= assignment ':' boolean-literal

precedence-group-associativity ::= "associativity" ':' "left"
precedence-group-associativity ::= "associativity" ':' "right"
precedence-group-associativity ::= "associativity" ':' "none"

precedence-group-names ::= precedence-group-name | precedence-group-name ',' precedence-group-names
precedence-group-name ::= identifier

//Grammar of a declaration modifier

declaration-modifier ::= "class" | "convenience" | "dynamic" | "final" | "infix" | "lazy" | "optional" | "override" | "postfix" | "prefix" | "required" | "static" | "unowned" | "unowned(safe)" | "unowned(unsafe)" | "weak"
declaration-modifier ::= access-level-modifier
declaration-modifier ::= mutation-modifier
declaration-modifier ::= actor-isolation-modifier
declaration-modifiers ::= declaration-modifier declaration-modifiers?

access-level-modifier ::= "private" | "private(set)"
access-level-modifier ::= "fileprivate" | "fileprivate(set)"
access-level-modifier ::= "internal" | "internal(set)"
access-level-modifier ::= "package" | "package(set)"
access-level-modifier ::= "public" | "public(set)"
access-level-modifier ::= "open" | "open(set)"

mutation-modifier ::= "mutating" | "nonmutating"

actor-isolation-modifier ::= "nonisolated"

//Attributes
//Grammar of an attribute

attribute ::= '@' attribute-name attribute-argument-clause?
attribute-name ::= identifier
attribute-argument-clause ::= '(' balanced-tokens? ')'
attributes ::= attribute attributes?

balanced-tokens ::= balanced-token balanced-tokens?
balanced-token ::= '(' balanced-tokens? ')'
balanced-token ::= '[' balanced-tokens? ']'
balanced-token ::= '{' balanced-tokens? '}'
///balanced-token ::= Any identifier, keyword, literal, or operator
///balanced-token ::= Any punctuation except (, ), [, ], {, or }

//Patterns
//Grammar of a pattern

pattern ::= wildcard-pattern type-annotation?
pattern ::= identifier-pattern type-annotation?
pattern ::= value-binding-pattern
pattern ::= tuple-pattern type-annotation?
pattern ::= enum-case-pattern
pattern ::= optional-pattern
pattern ::= type-casting-pattern
pattern ::= expression-pattern

//Grammar of a wildcard pattern

wildcard-pattern ::= '_'

//Grammar of an identifier pattern

identifier-pattern ::= identifier

//Grammar of a value-binding pattern

value-binding-pattern ::= "var" pattern | "let" pattern

//Grammar of a tuple pattern

tuple-pattern ::= '(' tuple-pattern-element-list? ')'
tuple-pattern-element-list ::= tuple-pattern-element | tuple-pattern-element ',' tuple-pattern-element-list
tuple-pattern-element ::= pattern | identifier ':' pattern

//Grammar of an enumeration case pattern

enum-case-pattern ::= type-identifier? '.' enum-case-name tuple-pattern?

//Grammar of an optional pattern

optional-pattern ::= identifier-pattern ?

//Grammar of a type casting pattern

type-casting-pattern ::= is-pattern | as-pattern
is-pattern ::= "is" type
as-pattern ::= pattern "as" type

//Grammar of an expression pattern

expression-pattern ::= expression

//Generic Parameters and Arguments
//Grammar of a generic parameter clause

generic-parameter-clause ::= '<' generic-parameter-list '>'
generic-parameter-list ::= generic-parameter | generic-parameter ',' generic-parameter-list
generic-parameter ::= type-name
generic-parameter ::= type-name ':' type-identifier
generic-parameter ::= type-name ':' protocol-composition-type

generic-where-clause ::= "where" requirement-list
requirement-list ::= requirement | requirement ',' requirement-list
requirement ::= conformance-requirement | same-type-requirement

conformance-requirement ::= type-identifier ':' type-identifier
conformance-requirement ::= type-identifier ':' protocol-composition-type
same-type-requirement ::= type-identifier "==" type

//Grammar of a generic argument clause

generic-argument-clause ::= '<' generic-argument-list '>'
generic-argument-list ::= generic-argument | generic-argument ',' generic-argument-list
generic-argument ::= type

Motivation

No response

Alternatives Considered

No response

@mingodad mingodad added the Enhancement New feature or request label Oct 23, 2024
@mingodad
Copy link
Author

Comparing with the EBNF generated from https://github.com/alex-pinkus/tree-sitter-swift with https://github.com/mingodad/plgh/blob/main/json2ebnf.js the grammar here seems to be missing several pieces (or the other way around).

//
// From tree-sitter-swift-alex-pinkus/src/grammar.json
//
//
// EBNF to generate railroad diagram at 
//      (IPV6) https://www.bottlecaps.de/rr/ui
//      (IPV4) https://rr.red-dove.com/ui
//

source_file ::=
	 shebang_line? ( _top_level_statement ( _semi _top_level_statement )* _semi? )?

_semi ::=
	 _implicit_semi
	| _explicit_semi

shebang_line ::=
	 '#!' [^#x0D#x0A]*

comment ::=
	 '//' '.'*

simple_identifier ::=
	/* [_\p{XID_Start}\p{Emoji}&&[^0-9#x23*]]('\p{EMod}'|'\x{FE0F}\x{20E3}'?)?([_\p{XID_Continue}\p{Emoji}\x{200D}]('\p{EMod}'|'\x{FE0F}\x{20E3}'?)?)*
	|*/ '`'[^#x0D#x0A` ]*'`'
	| '\$'[0-9]+
	//| ( '$' [_\p{XID_Start}\p{Emoji}&&[^0-9#x23*]]('\p{EMod}'|'\x{FE0F}\x{20E3}'?)?([_\p{XID_Continue}\p{Emoji}\x{200D}]('\p{EMod}'|'\x{FE0F}\x{20E3}'?)?)* )
	| _contextual_simple_identifier

_contextual_simple_identifier ::=
	 'actor'
	| 'async'
	| 'each'
	| 'lazy'
	| 'repeat'
	| 'package'
	| _parameter_ownership_modifier

identifier ::=
	 simple_identifier ( _dot simple_identifier )*

_basic_literal ::=
	 integer_literal
	| hex_literal
	| oct_literal
	| bin_literal
	| real_literal
	| boolean_literal
	| _string_literal
	| regex_literal
	| 'nil'

real_literal ::=
	 ( ( [0-9]+ ( '_'+ [0-9]+ )* ) ( [eE] [+-]? ( [0-9]+ ( '_'+ [0-9]+ )* ) ) | ( [0-9]+ ( '_'+ [0-9]+ )* )? '.' ( [0-9]+ ( '_'+ [0-9]+ )* ) ( [eE] [+-]? ( [0-9]+ ( '_'+ [0-9]+ )* ) )? )

integer_literal ::=
	 ( [1-9]? ( [0-9]+ ( '_'+ [0-9]+ )* ) )

hex_literal ::=
	 ( '0' [xX] ( [0-9a-fA-F]+ ( '_'+ [0-9a-fA-F]+ )* ) )

oct_literal ::=
	 ( '0' [oO] ( [0-7]+ ( '_'+ [0-7]+ )* ) )

bin_literal ::=
	 ( '0' [bB] ( [01]+ ( '_'+ [01]+ )* ) )

boolean_literal ::=
	 'true'
	| 'false'

_string_literal ::=
	 line_string_literal
	| multi_line_string_literal
	| raw_string_literal

line_string_literal ::=
	 '"'  ( _line_string_content | _interpolation )* '"' 

_line_string_content ::=
	 line_str_text
	| str_escaped_char

line_str_text ::=
	 [^\"]+

str_escaped_char ::=
	 _escaped_identifier
	| _uni_character_literal

_uni_character_literal ::=
	 '\\'  'u' '\{'[0-9a-fA-F]+'\}'

multi_line_string_literal ::=
	 '"""' ( _multi_line_string_content | _interpolation )* '"""'

raw_string_literal ::=
	 ( raw_str_part raw_str_interpolation raw_str_continuing_indicator? )* raw_str_end_part

raw_str_interpolation ::=
	 raw_str_interpolation_start _interpolation_contents ')'

raw_str_interpolation_start ::=
	 "#*("

_multi_line_string_content ::=
	 multi_line_str_text
	| str_escaped_char
	| '"' 

_interpolation ::=
	 '\(' _interpolation_contents ')'

_interpolation_contents ::=
	 value_argument ( ',' value_argument )*

_escaped_identifier ::=
	 '\'[0\tnr"'#x0A]

multi_line_str_text ::=
	 [^\"]+

regex_literal ::=
	 _extended_regex_literal
	| _multiline_regex_literal
	| _oneline_regex_literal

_extended_regex_literal ::=
	 '#\/'(('\/'[^#x23])|[^#x0A])+'\/#'

_multiline_regex_literal ::=
	 '#\/#x0A' ('\/'[^#x23]|[^/])*?'#x0A\/#'

_oneline_regex_literal ::=
	 '/' [^ #x09#x0A]?[^/#x0A]*[^ #x09#x0A/] '/'

type_annotation ::=
	 ':' _possibly_implicitly_unwrapped_type

_possibly_implicitly_unwrapped_type ::=
	 _type '!'?

_type ::=
	 type_modifiers? _unannotated_type

_unannotated_type ::=
	 user_type | tuple_type | function_type | array_type | dictionary_type | optional_type | metatype | opaque_type | existential_type | protocol_composition_type | type_parameter_pack | type_pack_expansion

user_type ::=
	 _simple_user_type ( _dot _simple_user_type )*

_simple_user_type ::=
	 simple_identifier type_arguments?

tuple_type ::=
	 '(' ( tuple_type_item ( ',' tuple_type_item )* )? ')'
	| _parenthesized_type

tuple_type_item ::=
	 _tuple_type_item_identifier? parameter_modifiers? _type

_tuple_type_item_identifier ::=
	 wildcard_pattern? simple_identifier ':'

function_type ::=
	 ( tuple_type | _unannotated_type ) _async_keyword? throws? _arrow_operator _type

array_type ::=
	 '[' _type ']'

dictionary_type ::=
	 '[' _type ':' _type ']'

optional_type ::=
	 ( user_type | tuple_type | array_type | dictionary_type ) _immediate_quest+

metatype ::=
	 _unannotated_type '.' ( 'Type' | 'Protocol' )

_quest ::=
	 '?'

_immediate_quest ::=
	 '?'

opaque_type ::=
	 'some' _unannotated_type

existential_type ::=
	 'any' _unannotated_type

type_parameter_pack ::=
	 'each' _unannotated_type

type_pack_expansion ::=
	 'repeat' _unannotated_type

protocol_composition_type ::=
	 _unannotated_type ( '&' _unannotated_type )+

_expression ::=
	 simple_identifier | _unary_expression | _binary_expression | ternary_expression | _primary_expression | if_statement | switch_statement | assignment | value_parameter_pack | value_pack_expansion | _expression _immediate_quest

_unary_expression ::=
	 postfix_expression
	| call_expression
	| constructor_expression
	| navigation_expression
	| prefix_expression
	| as_expression
	| selector_expression
	| open_start_range_expression
	| open_end_range_expression

postfix_expression ::=
	 _expression _postfix_unary_operator

constructor_expression ::=
	 ( array_type | dictionary_type | user_type ) constructor_suffix

_parenthesized_type ::=
	 '(' ( opaque_type | existential_type | dictionary_type ) ')'

navigation_expression ::=
	 ( _navigable_type_expression | _expression | _parenthesized_type ) navigation_suffix

_navigable_type_expression ::=
	 user_type
	| array_type
	| dictionary_type

open_start_range_expression ::=
	 _range_operator _expression

_range_operator ::=
	 _open_ended_range_operator
	| _three_dot_operator

open_end_range_expression ::=
	 _expression _three_dot_operator

prefix_expression ::=
	 _prefix_unary_operator ( _expression | ( 'async' | 'if' | 'switch' ) )

as_expression ::=
	 _expression as_operator _type

selector_expression ::=
	 '#selector' '(' ( 'getter:' | 'setter:' )? _expression ')'

_binary_expression ::=
	 multiplicative_expression
	| additive_expression
	| range_expression
	| infix_expression
	| nil_coalescing_expression
	| check_expression
	| equality_expression
	| comparison_expression
	| conjunction_expression
	| disjunction_expression
	| bitwise_operation

multiplicative_expression ::=
	 _expression _multiplicative_operator _expression

additive_expression ::=
	 _expression _additive_operator _expression

range_expression ::=
	 _expression _range_operator _expr_hack_at_ternary_binary_suffix

infix_expression ::=
	 _expression custom_operator _expr_hack_at_ternary_binary_suffix

nil_coalescing_expression ::=
	 _expression _nil_coalescing_operator _expr_hack_at_ternary_binary_suffix

check_expression ::=
	 _expression _is_operator _type

comparison_expression ::=
	 _expression _comparison_operator _expr_hack_at_ternary_binary_suffix

equality_expression ::=
	 _expression _equality_operator _expr_hack_at_ternary_binary_suffix

conjunction_expression ::=
	 _expression _conjunction_operator _expr_hack_at_ternary_binary_suffix

disjunction_expression ::=
	 _expression _disjunction_operator _expr_hack_at_ternary_binary_suffix

bitwise_operation ::=
	 _expression _bitwise_binary_operator _expr_hack_at_ternary_binary_suffix

custom_operator ::=
	 [\/]+[*]+
	| _custom_operator

navigation_suffix ::=
	 _dot ( simple_identifier | integer_literal )

call_suffix ::=
	 value_arguments | _fn_call_lambda_arguments | value_arguments _fn_call_lambda_arguments

constructor_suffix ::=
	 _constructor_value_arguments | _fn_call_lambda_arguments | _constructor_value_arguments _fn_call_lambda_arguments

_constructor_value_arguments ::=
	 '(' ( value_argument ( ',' value_argument )* )? ')'

_fn_call_lambda_arguments ::=
	 lambda_literal ( simple_identifier ':' lambda_literal )*

type_arguments ::=
	 '<' _type ( ',' _type )* '>'

value_arguments ::=
	 ( '(' ( value_argument ( ',' value_argument )* )? ')' | '[' ( value_argument ( ',' value_argument )* )? ']' )

value_argument_label ::=
	 simple_identifier | 'if' | 'switch'

value_argument ::=
	 type_modifiers? ( ( value_argument_label ':' )+ | ( value_argument_label ':' )? _expression )

try_expression ::=
	 try_operator ( _expression | _binary_expression | call_expression | ternary_expression )

await_expression ::=
	 _await_operator ( _expression | call_expression | ternary_expression )

_await_operator ::=
	 'await'

ternary_expression ::=
	 _expression _quest _expression ':' _expr_hack_at_ternary_binary_suffix

_expr_hack_at_ternary_binary_suffix ::=
	 _expression | expr_hack_at_ternary_binary_call

expr_hack_at_ternary_binary_call ::=
	 _expression expr_hack_at_ternary_binary_call_suffix

expr_hack_at_ternary_binary_call_suffix ::=
	 value_arguments

call_expression ::=
	 _expression call_suffix

_primary_expression ::=
	 tuple_expression
	| _basic_literal
	| lambda_literal
	| _special_literal
	| _playground_literal
	| array_literal
	| dictionary_literal
	| self_expression
	| super_expression
	| try_expression
	| await_expression
	| _referenceable_operator
	| key_path_expression
	| key_path_string_expression
	| _three_dot_operator

tuple_expression ::=
	 '(' ( simple_identifier ':' )? _expression ( ',' ( simple_identifier ':' )? _expression )* ')'

array_literal ::=
	 '[' ( _expression ( ',' _expression )* )? ','? ']'

dictionary_literal ::=
	 '[' ( ':' | _dictionary_literal_item ( ',' _dictionary_literal_item )* ) ','? ']'

_dictionary_literal_item ::=
	 _expression ':' _expression

_special_literal ::=
	 '#file'
	| '#fileID'
	| '#filePath'
	| '#line'
	| '#column'
	| '#function'
	| '#dsohandle'

_playground_literal ::=
	 ( '#colorLiteral' | '#fileLiteral' | '#imageLiteral' ) '(' simple_identifier ':' _expression ( ',' simple_identifier ':' _expression )* ')'

lambda_literal ::=
	 ( '{' | '^{' ) _lambda_type_declaration? statements? '}'

_lambda_type_declaration ::=
	 attribute* capture_list lambda_function_type? 'in'

capture_list ::=
	 '[' capture_list_item ( ',' capture_list_item )* ']'

capture_list_item ::=
	 self_expression
	| ownership_modifier? simple_identifier ( _equal_sign _expression )?

lambda_function_type ::=
	 ( lambda_function_type_parameters | '(' lambda_function_type_parameters? ')' ) _async_keyword? throws? ( _arrow_operator _possibly_implicitly_unwrapped_type )?

lambda_function_type_parameters ::=
	 lambda_parameter ( ',' lambda_parameter )*

lambda_parameter ::=
	 ( self_expression | simple_identifier | simple_identifier? simple_identifier ':' parameter_modifiers? _possibly_implicitly_unwrapped_type )

self_expression ::=
	 'self'

super_expression ::=
	 'super'

_else_options ::=
	 _block
	| if_statement

if_statement ::=
	 'if' _if_condition_sequence_item ( ',' _if_condition_sequence_item )* _block ( else _else_options )?

_if_condition_sequence_item ::=
	 _if_let_binding
	| _expression
	| availability_condition

_if_let_binding ::=
	 _direct_or_indirect_binding ( _equal_sign _expression )? where_clause?

guard_statement ::=
	 'guard' _if_condition_sequence_item ( ',' _if_condition_sequence_item )* else _block

switch_statement ::=
	 'switch' _expression '{' switch_entry* '}'

switch_entry ::=
	 modifiers? ( 'case' switch_pattern ( where_keyword _expression )? ( ',' switch_pattern )* | default_keyword ) ':' statements 'fallthrough'?

switch_pattern ::=
	 _binding_pattern_with_expr

do_statement ::=
	 'do' _block catch_block*

catch_block ::=
	 catch_keyword _binding_pattern_no_expr? where_clause? _block

where_clause ::=
	 where_keyword _expression

key_path_expression ::=
	 '\\'  ( _simple_user_type | array_type | dictionary_type )? ( '.' _key_path_component )*

key_path_string_expression ::=
	 '#keyPath' '(' _expression ')'

_key_path_component ::=
	 simple_identifier _key_path_postfixes* | _key_path_postfixes+

_key_path_postfixes ::=
	 '?'
	| bang
	| 'self'
	| '[' ( value_argument ( ',' value_argument )* )? ']'

try_operator ::=
	 'try' ( _try_operator_type | _fake_try_bang )

_try_operator_type ::=
	 '!'
	| '?'

_assignment_and_operator ::=
	 '+='
	| '-='
	| '*='
	| '/='
	| '%='
	| _equal_sign

_equality_operator ::=
	 '!='
	| '!=='
	| _eq_eq
	| '==='

_comparison_operator ::=
	 '<'
	| '>'
	| '<='
	| '>='

_three_dot_operator ::=
	 '...'

_open_ended_range_operator ::=
	 '..<'

_is_operator ::=
	 'is'

_additive_operator ::=
	 _plus_then_ws
	| _minus_then_ws
	| '+'
	| '-'

_multiplicative_operator ::=
	 '*'
	| '/'
	| '%'

as_operator ::=
	 _as
	| _as_quest
	| _as_bang

_prefix_unary_operator ::=
	 '++' | '--' | '-' | '+' | bang | '&' | '~' | _dot | custom_operator

_bitwise_binary_operator ::=
	 '&'
	| '|'
	| '^'
	| '<<'
	| '>>'

_postfix_unary_operator ::=
	 '++'
	| '--'
	| bang

directly_assignable_expression ::=
	 _expression

statements ::=
	 _local_statement ( _semi _local_statement )* _semi?

_local_statement ::=
	 _expression
	| _local_declaration
	| _labeled_statement
	| control_transfer_statement

_top_level_statement ::=
	 _expression
	| _global_declaration
	| _labeled_statement
	| _throw_statement

_block ::=
	 '{' statements? '}'

_labeled_statement ::=
	 statement_label? ( for_statement | while_statement | repeat_while_statement | do_statement | if_statement | guard_statement | switch_statement )

statement_label ::=
	 [a-zA-Z_][a-zA-Z_0-9]*':'

for_statement ::=
	 'for' try_operator? _await_operator? _binding_pattern_no_expr type_annotation? 'in' _for_statement_collection where_clause? _block

_for_statement_collection ::=
	 _expression
	| for_statement_await

for_statement_await ::=
	 _await_operator _expression

while_statement ::=
	 'while' _if_condition_sequence_item ( ',' _if_condition_sequence_item )* '{' statements? '}'

repeat_while_statement ::=
	 'repeat' '{' statements? '}' _implicit_semi* 'while' _if_condition_sequence_item ( ',' _if_condition_sequence_item )*

control_transfer_statement ::=
	 _throw_statement
	| _optionally_valueful_control_keyword _expression?

_throw_statement ::=
	 throw_keyword _expression

throw_keyword ::=
	 'throw'

_optionally_valueful_control_keyword ::=
	 'return'
	| 'continue'
	| 'break'
	| 'yield'

assignment ::=
	 directly_assignable_expression _assignment_and_operator _expression

value_parameter_pack ::=
	 'each' _expression

value_pack_expansion ::=
	 'repeat' _expression

availability_condition ::=
	 ( '#available' | '#unavailable' ) '(' _availability_argument ( ',' _availability_argument )* ')'

_availability_argument ::=
	 identifier integer_literal ( '.' integer_literal )*
	| '*'

_global_declaration ::=
	 import_declaration
	| property_declaration
	| typealias_declaration
	| function_declaration
	| init_declaration
	| class_declaration
	| protocol_declaration
	| operator_declaration
	| precedence_group_declaration
	| associatedtype_declaration
	| macro_declaration

_type_level_declaration ::=
	 import_declaration
	| property_declaration
	| typealias_declaration
	| function_declaration
	| init_declaration
	| class_declaration
	| protocol_declaration
	| deinit_declaration
	| subscript_declaration
	| operator_declaration
	| precedence_group_declaration
	| associatedtype_declaration

_local_declaration ::=
	 _local_property_declaration
	| _local_typealias_declaration
	| _local_function_declaration
	| _local_class_declaration

_local_property_declaration ::=
	 _locally_permitted_modifiers? _modifierless_property_declaration

_local_typealias_declaration ::=
	 _locally_permitted_modifiers? _modifierless_typealias_declaration

_local_function_declaration ::=
	 _locally_permitted_modifiers? _modifierless_function_declaration

_local_class_declaration ::=
	 _locally_permitted_modifiers? _modifierless_class_declaration

import_declaration ::=
	 modifiers? 'import' _import_kind? identifier

_import_kind ::=
	 'typealias'
	| 'struct'
	| 'class'
	| 'enum'
	| 'protocol'
	| 'let'
	| 'var'
	| 'func'

protocol_property_declaration ::=
	 modifiers? _binding_kind_and_pattern type_annotation? type_constraints? protocol_property_requirements

protocol_property_requirements ::=
	 '{' ( getter_specifier | setter_specifier )* '}'

property_declaration ::=
	 modifiers? _modifierless_property_declaration

_modifierless_property_declaration ::=
	 _possibly_async_binding_pattern_kind _single_modifierless_property_declaration ( ',' _single_modifierless_property_declaration )*

_single_modifierless_property_declaration ::=
	 _no_expr_pattern_already_bound type_annotation? type_constraints? ( _expression_with_willset_didset | _expression_without_willset_didset | willset_didset_block | computed_property )?

_expression_with_willset_didset ::=
	 _equal_sign _expression willset_didset_block

_expression_without_willset_didset ::=
	 _equal_sign _expression

willset_didset_block ::=
	 '{' willset_clause didset_clause? '}'
	| '{' didset_clause willset_clause? '}'

willset_clause ::=
	 modifiers? 'willSet' ( '(' simple_identifier ')' )? _block

didset_clause ::=
	 modifiers? 'didSet' ( '(' simple_identifier ')' )? _block

typealias_declaration ::=
	 modifiers? _modifierless_typealias_declaration

_modifierless_typealias_declaration ::=
	 'typealias' simple_identifier type_parameters? _equal_sign _type

function_declaration ::=
	 _bodyless_function_declaration function_body

_modifierless_function_declaration ::=
	 _modifierless_function_declaration_no_body function_body

_bodyless_function_declaration ::=
	 modifiers? 'class'? _modifierless_function_declaration_no_body

_modifierless_function_declaration_no_body ::=
	 _non_constructor_function_decl type_parameters? _function_value_parameters _async_keyword? throws? ( _arrow_operator _possibly_implicitly_unwrapped_type )? type_constraints?

function_body ::=
	 _block

macro_declaration ::=
	 _macro_head simple_identifier type_parameters? _macro_signature macro_definition? type_constraints?

_macro_head ::=
	 modifiers? 'macro'

_macro_signature ::=
	 _function_value_parameters ( _arrow_operator _unannotated_type )?

macro_definition ::=
	 _equal_sign ( _expression | external_macro_definition )

external_macro_definition ::=
	 '#externalMacro' value_arguments

class_declaration ::=
	 modifiers? _modifierless_class_declaration

_modifierless_class_declaration ::=
	 ( 'class' | 'struct' | 'actor' ) simple_identifier type_parameters? ( ':' _inheritance_specifiers )? type_constraints? class_body | 'extension' _unannotated_type type_parameters? ( ':' _inheritance_specifiers )? type_constraints? class_body | 'indirect'? 'enum' simple_identifier type_parameters? ( ':' _inheritance_specifiers )? type_constraints? enum_class_body

class_body ::=
	 '{' _class_member_declarations? '}'

_inheritance_specifiers ::=
	 _annotated_inheritance_specifier ( ( ',' | '&' ) _annotated_inheritance_specifier )*

inheritance_specifier ::=
	 ( user_type | function_type )

_annotated_inheritance_specifier ::=
	 attribute* inheritance_specifier

type_parameters ::=
	 '<' type_parameter ( ',' type_parameter )* type_constraints? '>'

type_parameter ::=
	 type_parameter_modifiers? _type_parameter_possibly_packed ( ':' _type )?

_type_parameter_possibly_packed ::=
	 simple_identifier
	| type_parameter_pack

type_constraints ::=
	 where_keyword type_constraint ( ',' type_constraint )*

type_constraint ::=
	 inheritance_constraint
	| equality_constraint

inheritance_constraint ::=
	 attribute* _constrained_type ':' _possibly_implicitly_unwrapped_type

equality_constraint ::=
	 attribute* _constrained_type ( _equal_sign | _eq_eq ) _type

_constrained_type ::=
	 identifier
	| _unannotated_type ( '.' simple_identifier ( '.' simple_identifier )* )?

_class_member_separator ::=
	 _semi
	| multiline_comment

_class_member_declarations ::=
	 _type_level_declaration ( _class_member_separator _type_level_declaration )* _class_member_separator?

_function_value_parameters ::=
	 ( '(' ( _function_value_parameter ( ',' _function_value_parameter )* )? ')' )+

_function_value_parameter ::=
	 attribute? parameter ( _equal_sign _expression )?

parameter ::=
	 simple_identifier? simple_identifier ':' parameter_modifiers? _possibly_implicitly_unwrapped_type _three_dot_operator?

_non_constructor_function_decl ::=
	 'func' ( simple_identifier | _referenceable_operator )

_referenceable_operator ::=
	 custom_operator
	| _comparison_operator
	| _additive_operator
	| _multiplicative_operator
	| _equality_operator
	| _comparison_operator
	| _assignment_and_operator
	| '++'
	| '--'
	| bang
	| '~'
	| '|'
	| '^'
	| '<<'
	| '>>'
	| '&'

_equal_sign ::=
	 _eq_custom

_eq_eq ::=
	 _eq_eq_custom

_dot ::=
	 _dot_custom

_arrow_operator ::=
	 _arrow_operator_custom

_conjunction_operator ::=
	 _conjunction_operator_custom

_disjunction_operator ::=
	 _disjunction_operator_custom

_nil_coalescing_operator ::=
	 _nil_coalescing_operator_custom

_as ::=
	 _as_custom

_as_quest ::=
	 _as_quest_custom

_as_bang ::=
	 _as_bang_custom

bang ::=
	 _bang_custom
	| '!'

_async_keyword ::=
	 _async_keyword_custom

_async_modifier ::=
	 'async'

throws ::=
	 _throws_keyword
	| _rethrows_keyword

enum_class_body ::=
	 '{' ( enum_entry | _type_level_declaration )* '}'

enum_entry ::=
	 modifiers? 'indirect'? 'case' simple_identifier _enum_entry_suffix? ( ',' simple_identifier _enum_entry_suffix? )* ';'?

_enum_entry_suffix ::=
	 enum_type_parameters
	| _equal_sign _expression

enum_type_parameters ::=
	 '(' ( ( wildcard_pattern? simple_identifier ':' )? _type ( _equal_sign _expression )? ( ',' ( wildcard_pattern? simple_identifier ':' )? _type ( _equal_sign _expression )? )* )? ')'

protocol_declaration ::=
	 modifiers? 'protocol' simple_identifier type_parameters? ( ':' _inheritance_specifiers )? type_constraints? protocol_body

protocol_body ::=
	 '{' _protocol_member_declarations? '}'

_protocol_member_declarations ::=
	 _protocol_member_declaration ( _semi _protocol_member_declaration )* _semi?

_protocol_member_declaration ::=
	 ( _bodyless_function_declaration function_body? )
	| init_declaration
	| deinit_declaration
	| protocol_property_declaration
	| typealias_declaration
	| associatedtype_declaration
	| subscript_declaration

init_declaration ::=
	 modifiers? 'class'? 'init' ( _quest | bang )? type_parameters? _function_value_parameters _async_keyword? throws? type_constraints? function_body?

deinit_declaration ::=
	 modifiers? 'deinit' function_body

subscript_declaration ::=
	 modifiers? 'subscript' type_parameters? _function_value_parameters ( _arrow_operator _possibly_implicitly_unwrapped_type )? type_constraints? computed_property

computed_property ::=
	 '{' ( statements | ( computed_getter | computed_setter | computed_modify )* ) '}'

computed_getter ::=
	 attribute* getter_specifier _block?

computed_modify ::=
	 attribute* modify_specifier _block?

computed_setter ::=
	 attribute* setter_specifier ( '(' simple_identifier ')' )? _block?

getter_specifier ::=
	 mutation_modifier? 'get' _getter_effects?

setter_specifier ::=
	 mutation_modifier? 'set'

modify_specifier ::=
	 mutation_modifier? '_modify'

_getter_effects ::=
	 ( _async_keyword | throws )+

operator_declaration ::=
	 ( 'prefix' | 'infix' | 'postfix' ) 'operator' _referenceable_operator ( ':' simple_identifier )? deprecated_operator_declaration_body?

deprecated_operator_declaration_body ::=
	 '{' ( simple_identifier | _basic_literal )* '}'

precedence_group_declaration ::=
	 'precedencegroup' simple_identifier '{' precedence_group_attributes? '}'

precedence_group_attributes ::=
	 precedence_group_attribute+

precedence_group_attribute ::=
	 simple_identifier ':' ( simple_identifier | boolean_literal )

associatedtype_declaration ::=
	 modifiers? 'associatedtype' simple_identifier ( ':' _type )? type_constraints? ( _equal_sign _type )?

attribute ::=
	 '@' user_type ( '(' _attribute_argument ( ',' _attribute_argument )* ')' )?

_attribute_argument ::=
	 simple_identifier ':' _expression
	| _expression
	| ( simple_identifier ':' )+
	| simple_identifier+ integer_literal ( '.' integer_literal )*

_universally_allowed_pattern ::=
	 wildcard_pattern
	| _tuple_pattern
	| _type_casting_pattern
	| _case_pattern

_bound_identifier ::=
	 simple_identifier

_binding_pattern_no_expr ::=
	 ( _universally_allowed_pattern | _binding_pattern | _bound_identifier ) _quest?

_no_expr_pattern_already_bound ::=
	 ( _universally_allowed_pattern | _bound_identifier ) _quest?

_binding_pattern_with_expr ::=
	 ( _universally_allowed_pattern | _binding_pattern | _expression ) _quest?

_non_binding_pattern_with_expr ::=
	 ( _universally_allowed_pattern | _expression ) _quest?

_direct_or_indirect_binding ::=
	 ( _binding_kind_and_pattern | 'case' _binding_pattern_no_expr ) type_annotation?

value_binding_pattern ::=
	 ( 'var' | 'let' )

_possibly_async_binding_pattern_kind ::=
	 _async_modifier? value_binding_pattern

_binding_kind_and_pattern ::=
	 _possibly_async_binding_pattern_kind _no_expr_pattern_already_bound

wildcard_pattern ::=
	 '_'

_tuple_pattern_item ::=
	 simple_identifier ':' _binding_pattern_with_expr
	| _binding_pattern_with_expr

_tuple_pattern ::=
	 '(' _tuple_pattern_item ( ',' _tuple_pattern_item )* ')'

_case_pattern ::=
	 'case'? user_type? _dot simple_identifier _tuple_pattern?

_type_casting_pattern ::=
	 'is' _type
	| _binding_pattern_no_expr _as _type

_binding_pattern ::=
	 'case'? value_binding_pattern _no_expr_pattern_already_bound

modifiers ::=
	 _non_local_scope_modifier | _locally_permitted_modifiers+

_locally_permitted_modifiers ::=
	 ( attribute | _locally_permitted_modifier )+

parameter_modifiers ::=
	 parameter_modifier+

_modifier ::=
	 _non_local_scope_modifier
	| _locally_permitted_modifier

_non_local_scope_modifier ::=
	 member_modifier
	| visibility_modifier
	| function_modifier
	| mutation_modifier
	| property_modifier
	| parameter_modifier

_locally_permitted_modifier ::=
	 ownership_modifier
	| inheritance_modifier
	| property_behavior_modifier

property_behavior_modifier ::=
	 'lazy'

type_modifiers ::=
	 attribute+

member_modifier ::=
	 'override'
	| 'convenience'
	| 'required'
	| 'nonisolated'

visibility_modifier ::=
	 ( 'public' | 'private' | 'internal' | 'fileprivate' | 'open' | 'package' ) ( '(' 'set' ')' )?

type_parameter_modifiers ::=
	 attribute+

function_modifier ::=
	 'infix'
	| 'postfix'
	| 'prefix'

mutation_modifier ::=
	 'mutating'
	| 'nonmutating'

property_modifier ::=
	 'static'
	| 'dynamic'
	| 'optional'
	| 'class'
	| 'distributed'

inheritance_modifier ::=
	 'final'

parameter_modifier ::=
	 'inout'
	| '@escaping'
	| '@autoclosure'
	| _parameter_ownership_modifier

ownership_modifier ::=
	 'weak'
	| 'unowned'
	| 'unowned(safe)'
	| 'unowned(unsafe)'

_parameter_ownership_modifier ::=
	 'borrowing'
	| 'consuming'

use_site_target ::=
	 ( 'property' | 'get' | 'set' | 'receiver' | 'param' | 'setparam' | 'delegate' ) ':'

directive ::=
	 '#if' '.'* | '#elseif' '.'* | '#else' '.'* | '#endif' '.'* | '#sourceLocation'([^#x0D#x0A]*)

diagnostic ::=
	 '#error'([^#x0D#x0A]*) | '#warning'([^#x0D#x0A]*)

unused_for_backward_compatibility ::=
	 'unused1'
	| 'unused2'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant