From 92678c0c0a648d7880b13c2f0bbbf91568638dcc Mon Sep 17 00:00:00 2001
From: Jan van Nunen <jan.van.nunen@tiobe.com>
Date: Wed, 2 Mar 2016 11:11:02 +0100
Subject: [PATCH] Added support for Swift to CPD.

The tokenizer uses the ANTLR4 grammar of the Tailor static analyzer for
Swift. (https://github.com/sleekbyte/tailor)
---
 pmd-dist/pom.xml                              |   5 +
 pmd-swift/pom.xml                             |  72 ++
 .../pmd/lang/swift/antlr4/Swift.g4            | 999 ++++++++++++++++++
 .../sourceforge/pmd/cpd/SwiftLanguage.java    |  19 +
 .../sourceforge/pmd/cpd/SwiftTokenizer.java   |  81 ++
 .../pmd/lang/swift/SwiftLanguageModule.java   |  25 +
 .../services/net.sourceforge.pmd.cpd.Language |   1 +
 .../net.sourceforge.pmd.lang.Language         |   1 +
 pmd-swift/src/site/markdown/index.md          |   3 +
 .../sourceforge/pmd/LanguageVersionTest.java  |  27 +
 .../pmd/cpd/SwiftTokenizerTest.java           |  37 +
 .../net/sourceforge/pmd/cpd/BTree.swift       | 890 ++++++++++++++++
 pom.xml                                       |   1 +
 13 files changed, 2161 insertions(+)
 create mode 100644 pmd-swift/pom.xml
 create mode 100644 pmd-swift/src/main/antlr4/net/sourceforge/pmd/lang/swift/antlr4/Swift.g4
 create mode 100644 pmd-swift/src/main/java/net/sourceforge/pmd/cpd/SwiftLanguage.java
 create mode 100644 pmd-swift/src/main/java/net/sourceforge/pmd/cpd/SwiftTokenizer.java
 create mode 100644 pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/SwiftLanguageModule.java
 create mode 100644 pmd-swift/src/main/resources/META-INF/services/net.sourceforge.pmd.cpd.Language
 create mode 100644 pmd-swift/src/main/resources/META-INF/services/net.sourceforge.pmd.lang.Language
 create mode 100644 pmd-swift/src/site/markdown/index.md
 create mode 100644 pmd-swift/src/test/java/net/sourceforge/pmd/LanguageVersionTest.java
 create mode 100644 pmd-swift/src/test/java/net/sourceforge/pmd/cpd/SwiftTokenizerTest.java
 create mode 100644 pmd-swift/src/test/resources/net/sourceforge/pmd/cpd/BTree.swift

diff --git a/pmd-dist/pom.xml b/pmd-dist/pom.xml
index dbb35aa39d..862e99911f 100644
--- a/pmd-dist/pom.xml
+++ b/pmd-dist/pom.xml
@@ -128,6 +128,11 @@
             <artifactId>pmd-ruby</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>net.sourceforge.pmd</groupId>
+            <artifactId>pmd-swift</artifactId>
+            <version>${project.version}</version>
+        </dependency>
         <dependency>
             <groupId>net.sourceforge.pmd</groupId>
             <artifactId>pmd-vm</artifactId>
diff --git a/pmd-swift/pom.xml b/pmd-swift/pom.xml
new file mode 100644
index 0000000000..65d9562637
--- /dev/null
+++ b/pmd-swift/pom.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>pmd-swift</artifactId>
+    <name>PMD Swift</name>
+
+    <parent>
+        <groupId>net.sourceforge.pmd</groupId>
+        <artifactId>pmd</artifactId>
+        <version>5.3.7-SNAPSHOT</version>
+    </parent>
+
+    <properties>
+        <antlr.version>4.5.2-1</antlr.version>
+        <config.basedir>${basedir}/../pmd-core</config.basedir>
+    </properties>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.antlr</groupId>
+                <artifactId>antlr4-maven-plugin</artifactId>
+                <version>${antlr.version}</version>
+                <configuration>
+                    <encoding>UTF-8</encoding>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>antlr</id>
+                        <goals>
+                            <goal>antlr4</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <plugin>
+                <artifactId>maven-resources-plugin</artifactId>
+                <configuration>
+                    <useDefaultDelimiters>false</useDefaultDelimiters>
+                    <delimiters>
+                        <delimiter>${*}</delimiter>
+                    </delimiters>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.antlr</groupId>
+            <artifactId>antlr4-runtime</artifactId>
+            <version>${antlr.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>net.sourceforge.pmd</groupId>
+            <artifactId>pmd-core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>net.sourceforge.pmd</groupId>
+            <artifactId>pmd-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/pmd-swift/src/main/antlr4/net/sourceforge/pmd/lang/swift/antlr4/Swift.g4 b/pmd-swift/src/main/antlr4/net/sourceforge/pmd/lang/swift/antlr4/Swift.g4
new file mode 100644
index 0000000000..3a8fef8af5
--- /dev/null
+++ b/pmd-swift/src/main/antlr4/net/sourceforge/pmd/lang/swift/antlr4/Swift.g4
@@ -0,0 +1,999 @@
+// Downloaded on 2016/03/02 from https://github.com/sleekbyte/tailor/blob/master/src/main/antlr/com/sleekbyte/tailor/antlr/Swift.g4
+
+/*
+ * [The "BSD license"]
+ *  Copyright (c) 2014 Terence Parr
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. The name of the author may not be used to endorse or promote products
+ *     derived from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ *  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Converted from Apple's doc, http://tinyurl.com/n8rkoue, to ANTLR's
+ * meta-language.
+ */
+grammar Swift;
+
+topLevel : (statement | expression)* EOF ;
+
+// Statements
+
+// GRAMMAR OF A STATEMENT
+
+statement
+ : declaration ';'?
+ | loopStatement ';'?
+ | branchStatement ';'?
+ | labeledStatement
+ | controlTransferStatement ';'?
+ | deferStatement ';' ?
+ | doStatement ':'?
+ | compilerControlStatement ';'?
+ | expression ';'?  // Keep expression last to handle ambiguity
+ ;
+
+statements : statement+ ;
+
+// GRAMMAR OF A LOOP STATEMENT
+
+loopStatement : forStatement
+ | forInStatement
+ | whileStatement
+ | repeatWhileStatement
+ ;
+
+// GRAMMAR OF A FOR STATEMENT
+
+// Swift Language Reference has expression? instead of expressionList?
+forStatement
+ : 'for' forInit? ';' expression? ';' expressionList? codeBlock
+ | 'for' '(' forInit?';' expression? ';' expressionList? ')' codeBlock
+ ;
+
+forInit : variableDeclaration | expressionList  ;
+
+// GRAMMAR OF A FOR_IN STATEMENT
+
+forInStatement : 'for' 'case'? pattern 'in' expression whereClause? codeBlock  ;
+
+// GRAMMAR OF A WHILE STATEMENT
+
+whileStatement : 'while' conditionClause codeBlock  ;
+
+// GRAMMAR OF A REPEAT WHILE STATEMENT
+
+repeatWhileStatement: 'repeat' codeBlock 'while' conditionClause ;
+
+// GRAMMAR OF A BRANCH STATEMENT
+
+branchStatement : ifStatement | guardStatement | switchStatement  ;
+
+// GRAMMAR OF AN IF STATEMENT
+
+ifStatement : 'if' conditionClause codeBlock elseClause? ;
+elseClause : 'else' codeBlock | 'else' ifStatement  ;
+
+// GRAMMAR OF A GUARD STATEMENT
+
+guardStatement : 'guard' conditionClause 'else' codeBlock ;
+
+// GRAMMAR OF A SWITCH STATEMENT
+
+switchStatement : 'switch' expression '{' switchCases? '}'  ;
+switchCases : switchCase switchCases? ;
+switchCase : caseLabel statements | defaultLabel statements  | caseLabel ';' | defaultLabel ';'  ;
+caseLabel : 'case' caseItemList ':' ;
+caseItemList : caseItem (',' caseItem)* ;
+caseItem: pattern whereClause? ;
+defaultLabel : 'default' ':' ;
+
+// GRAMMAR OF A LABELED STATEMENT
+
+labeledStatement : statementLabel loopStatement | statementLabel switchStatement  ;
+statementLabel : labelName ':' ;
+labelName : identifier  ;
+
+// GRAMMAR OF A CONTROL TRANSFER STATEMENT
+
+controlTransferStatement : breakStatement
+ | continueStatement
+ | fallthroughStatement
+ | returnStatement
+ | throwStatement
+ ;
+
+// GRAMMAR OF A BREAK STATEMENT
+
+breakStatement : 'break' labelName? ;
+
+// GRAMMAR OF A CONTINUE STATEMENT
+
+continueStatement : 'continue' labelName? ;
+
+// GRAMMAR OF A FALLTHROUGH STATEMENT
+
+fallthroughStatement : 'fallthrough'  ;
+
+// GRAMMAR OF A RETURN STATEMENT
+
+returnStatement : 'return' expression? ;
+
+// GRAMMAR OF A THROW STATEMENT
+
+throwStatement : 'throw' expression ;
+
+// GRAMMAR OF A DEFER STATEMENT
+
+deferStatement: 'defer' codeBlock ;
+
+// GRAMMAR OF A DO STATEMENT
+
+doStatement: 'do' codeBlock catchClauses? ;
+catchClauses: catchClause catchClauses? ;
+catchClause: 'catch' pattern? whereClause? codeBlock ;
+
+// GRAMMAR FOR CONDITION CLAUSES
+
+conditionClause : expression
+ | expression ',' conditionList
+ | conditionList
+ | availabilityCondition ',' expression
+ ;
+
+conditionList : condition (',' condition)* ;
+condition: availabilityCondition | caseCondition | optionalBindingCondition ;
+caseCondition: 'case' pattern initializer whereClause? ;
+// optionalBindingCondition is incorrect in the Swift Language Reference (missing a ',')
+optionalBindingCondition: optionalBindingHead (',' optionalBindingContinuationList)? whereClause? ;
+optionalBindingHead: 'let' pattern initializer | 'var' pattern initializer ;
+optionalBindingContinuationList: optionalBindingContinuation (',' optionalBindingContinuation)* ;
+optionalBindingContinuation: optionalBindingHead | pattern initializer ;
+
+whereClause: 'where' whereExpression ;
+whereExpression: expression ;
+
+// GRAMMAR OF AN AVAILABILITY CONDITION
+
+availabilityCondition: '#available' '(' availabilityArguments ')' ;
+availabilityArguments: availabilityArgument (',' availabilityArguments)* ;
+availabilityArgument: platformName platformVersion | '*' ;
+platformName: 'iOS' | 'iOSApplicationExtension' | 'OSX' | 'OSXApplicationExtension' | 'watchOS'
+ | 'watchOSApplicationExtension' | 'tvOS' | 'tvOSApplicationExtension' ;
+platformVersion: VersionLiteral | DecimalLiteral | FloatingPointLiteral ; // TODO: Find a way to make this only VersionLiteral
+
+// Generic Parameters and Arguments
+
+// GRAMMAR OF A GENERIC PARAMETER CLAUSE
+
+genericParameterClause : '<' genericParameterList requirementClause? '>'  ;
+genericParameterList : genericParameter (',' genericParameter)*  ;
+genericParameter : typeName | typeName ':' typeIdentifier | typeName ':' protocolCompositionType  ;
+requirementClause : 'where' requirementList  ;
+requirementList : requirement (',' requirement)*  ;
+requirement : conformanceRequirement | sameTypeRequirement  ;
+conformanceRequirement : typeIdentifier ':' typeIdentifier | typeIdentifier ':' protocolCompositionType  ;
+sameTypeRequirement : typeIdentifier '==' sType  ;
+
+// GRAMMAR OF A GENERIC ARGUMENT CLAUSE
+
+genericArgumentClause : '<' genericArgumentList '>'  ;
+genericArgumentList : genericArgument (',' genericArgument)* ;
+genericArgument : sType  ;
+
+// Declarations
+
+// GRAMMAR OF A DECLARATION
+
+declaration
+ : importDeclaration ';'?
+ | constantDeclaration ';'?
+ | variableDeclaration ';'?
+ | typealiasDeclaration ';'?
+ | functionDeclaration ';'?
+ | enumDeclaration ';'?
+ | structDeclaration ';'?
+ | classDeclaration ';'?
+ | protocolDeclaration ';'?
+ | initializerDeclaration ';'?
+ | deinitializerDeclaration ';'?
+ | extensionDeclaration ';'?
+ | subscriptDeclaration ';'?
+ | operatorDeclaration ';'?
+ // compiler-control-statement not in Swift Language Reference
+ | compilerControlStatement ';'?
+ ;
+
+declarations : declaration declarations? ;
+declarationModifiers : declarationModifier declarationModifiers? ;
+declarationModifier : 'class' | 'convenience' | 'dynamic' | 'final' | 'infix'
+ | 'lazy' | 'mutating' | 'nonmutating' | 'optional' | 'override' | 'postfix'
+ | 'prefix' | 'required' | 'static' | 'unowned' | 'unowned' '(' 'safe' ')'
+ | 'unowned' '(' 'unsafe' ')' | 'weak'
+ | accessLevelModifier ;
+
+accessLevelModifier : 'internal' | 'internal' '(' 'set' ')'
+ | 'private' | 'private' '(' 'set' ')'
+ | 'public' | 'public' '(' 'set' ')' ;
+accessLevelModifiers : accessLevelModifier accessLevelModifiers? ;
+
+// GRAMMAR OF A CODE BLOCK
+
+codeBlock : '{' statements? '}'  ;
+
+// GRAMMAR OF AN IMPORT DECLARATION
+
+importDeclaration : attributes? 'import' importKind? importPath  ;
+importKind : 'typealias' | 'struct' | 'class' | 'enum' | 'protocol' | 'var' | 'func'  ;
+importPath : importPathIdentifier | importPathIdentifier '.' importPath  ;
+importPathIdentifier : identifier | operator  ;
+
+// GRAMMAR OF A CONSTANT DECLARATION
+
+constantDeclaration : attributes? declarationModifiers? 'let' patternInitializerList  ;
+patternInitializerList : patternInitializer (',' patternInitializer)* ;
+patternInitializer : pattern initializer? ;
+initializer : '=' expression  ;
+
+// GRAMMAR OF A VARIABLE DECLARATION
+
+variableDeclaration
+ : variableDeclarationHead variableName typeAnnotation getterSetterBlock
+ | variableDeclarationHead variableName typeAnnotation getterSetterKeywordBlock
+ | variableDeclarationHead variableName initializer willSetDidSetBlock
+ | variableDeclarationHead variableName typeAnnotation initializer? willSetDidSetBlock
+ // keep this below getter and setter rules for ambiguity reasons
+ | variableDeclarationHead variableName typeAnnotation codeBlock
+ | variableDeclarationHead patternInitializerList
+ ;
+
+variableDeclarationHead : attributes? declarationModifiers? 'var'  ;
+variableName : identifier  ;
+getterSetterBlock : '{' getterClause setterClause?'}'  | '{' setterClause getterClause '}'  ;
+getterClause : attributes? 'get' codeBlock  ;
+setterClause : attributes? 'set' setterName? codeBlock  ;
+setterName : '(' identifier ')'  ;
+getterSetterKeywordBlock : '{' getterKeywordClause setterKeywordClause?'}' | '{' setterKeywordClause getterKeywordClause '}'  ;
+getterKeywordClause : attributes? 'get'  ;
+setterKeywordClause : attributes? 'set'  ;
+willSetDidSetBlock : '{' willSetClause didSetClause?'}' | '{' didSetClause willSetClause? '}'  ;
+willSetClause : attributes? 'willSet' setterName? codeBlock  ;
+didSetClause : attributes? 'didSet' setterName? codeBlock  ;
+
+// GRAMMAR OF A TYPE ALIAS DECLARATION
+
+typealiasDeclaration : typealiasHead typealiasAssignment  ;
+typealiasHead : attributes? accessLevelModifier? 'typealias' typealiasName  ;
+typealiasName : identifier  ;
+typealiasAssignment : '=' sType  ;
+
+// GRAMMAR OF A FUNCTION DECLARATION
+
+/* HACK: functionBody? is intentionally not used to force the parser to try and match a functionBody first
+ * This can be removed once we figure out how to enforce that statements are either separated by semi colons or new line characters
+ */
+functionDeclaration : functionHead functionName genericParameterClause? functionSignature functionBody
+ | functionHead functionName genericParameterClause? functionSignature
+ ;
+
+functionHead : attributes? declarationModifiers? 'func'  ;
+functionName : identifier |  operator  ;
+// rethrows is not marked as optional in the Swift Language Reference
+functionSignature : parameterClauses ('throws' | 'rethrows')? functionResult? ;
+functionResult : '->' attributes? sType  ;
+functionBody : codeBlock  ;
+parameterClauses : parameterClause parameterClauses? ;
+parameterClause : '(' ')' |  '(' parameterList '...'? ')'  ;
+parameterList : parameter (',' parameter)*  ;
+// Parameters don't have attributes in the Swift Language Reference
+parameter : attributes? 'inout'? 'let'? '#'? externalParameterName? localParameterName typeAnnotation? defaultArgumentClause?
+ | 'inout'? 'var' '#'? externalParameterName? localParameterName typeAnnotation? defaultArgumentClause?
+ | attributes? sType
+ | externalParameterName? localParameterName typeAnnotation '...'
+ ;
+externalParameterName : identifier | '_'  ;
+localParameterName : identifier | '_'  ;
+defaultArgumentClause : '=' expression  ;
+
+// GRAMMAR OF AN ENUMERATION DECLARATION
+
+enumDeclaration : attributes? accessLevelModifier? enumDef  ;
+enumDef: unionStyleEnum | rawValueStyleEnum  ;
+unionStyleEnum : 'indirect'? 'enum' enumName genericParameterClause? typeInheritanceClause? '{' unionStyleEnumMembers?'}'  ;
+unionStyleEnumMembers : unionStyleEnumMember unionStyleEnumMembers? ;
+unionStyleEnumMember : declaration | unionStyleEnumCaseClause ';'? ;
+unionStyleEnumCaseClause : attributes? 'indirect'? 'case' unionStyleEnumCaseList  ;
+unionStyleEnumCaseList : unionStyleEnumCase (',' unionStyleEnumCase)*  ;
+unionStyleEnumCase : enumCaseName tupleType? ;
+enumName : identifier  ;
+enumCaseName : identifier  ;
+// typeInheritanceClause is not optional in the Swift Language Reference
+rawValueStyleEnum : 'enum' enumName genericParameterClause? typeInheritanceClause? '{' rawValueStyleEnumMembers?'}'  ;
+rawValueStyleEnumMembers : rawValueStyleEnumMember rawValueStyleEnumMembers? ;
+rawValueStyleEnumMember : declaration | rawValueStyleEnumCaseClause  ;
+rawValueStyleEnumCaseClause : attributes? 'case' rawValueStyleEnumCaseList  ;
+rawValueStyleEnumCaseList : rawValueStyleEnumCase (',' rawValueStyleEnumCase)*   ;
+rawValueStyleEnumCase : enumCaseName rawValueAssignment? ;
+rawValueAssignment : '=' literal  ;
+
+// GRAMMAR OF A STRUCTURE DECLARATION
+
+structDeclaration : attributes? accessLevelModifier? 'struct' structName genericParameterClause? typeInheritanceClause? structBody  ;
+structName : identifier  ;
+structBody : '{' declarations?'}'  ;
+
+// GRAMMAR OF A CLASS DECLARATION
+
+// declarationModifier missing in Swift Language Reference
+classDeclaration : attributes? declarationModifier* 'class' className genericParameterClause? typeInheritanceClause? classBody  ;
+className : identifier ;
+classBody : '{' declarations? '}'  ;
+
+// GRAMMAR OF A PROTOCOL DECLARATION
+
+protocolDeclaration : attributes? accessLevelModifier? 'protocol' protocolName typeInheritanceClause? protocolBody  ;
+protocolName : identifier  ;
+protocolBody : '{' protocolMemberDeclarations?'}'  ;
+protocolMemberDeclaration : protocolPropertyDeclaration ';'?
+ | protocolMethodDeclaration ';'?
+ | protocolInitializerDeclaration ';'?
+ | protocolSubscriptDeclaration ';'?
+ | protocolAssociatedTypeDeclaration ';'?
+ ;
+protocolMemberDeclarations : protocolMemberDeclaration protocolMemberDeclarations? ;
+
+// GRAMMAR OF A PROTOCOL PROPERTY DECLARATION
+
+protocolPropertyDeclaration : variableDeclarationHead variableName typeAnnotation getterSetterKeywordBlock  ;
+
+// GRAMMAR OF A PROTOCOL METHOD DECLARATION
+
+protocolMethodDeclaration : functionHead functionName genericParameterClause? functionSignature  ;
+
+// GRAMMAR OF A PROTOCOL INITIALIZER DECLARATION
+
+protocolInitializerDeclaration : initializerHead genericParameterClause? parameterClause ('throws' | 'rethrows')? ;
+
+// GRAMMAR OF A PROTOCOL SUBSCRIPT DECLARATION
+
+protocolSubscriptDeclaration : subscriptHead subscriptResult getterSetterKeywordBlock  ;
+
+// GRAMMAR OF A PROTOCOL ASSOCIATED TYPE DECLARATION
+
+protocolAssociatedTypeDeclaration : typealiasHead typeInheritanceClause? typealiasAssignment? ;
+
+// GRAMMAR OF AN INITIALIZER DECLARATION
+
+initializerDeclaration : initializerHead genericParameterClause? parameterClause ('throws' | 'rethrows')? initializerBody  ;
+initializerHead : attributes? declarationModifiers? 'init' ('?' | '!')?  ;
+initializerBody : codeBlock  ;
+
+// GRAMMAR OF A DEINITIALIZER DECLARATION
+
+deinitializerDeclaration : attributes? 'deinit' codeBlock  ;
+
+// GRAMMAR OF AN EXTENSION DECLARATION
+
+// attributes, requirementClause missing in the Swift Language Reference
+extensionDeclaration : attributes? accessLevelModifier? 'extension' typeIdentifier requirementClause? typeInheritanceClause? extensionBody  ;
+extensionBody : '{' declarations?'}'  ;
+
+// GRAMMAR OF A SUBSCRIPT DECLARATION
+
+subscriptDeclaration : subscriptHead subscriptResult getterSetterBlock
+ | subscriptHead subscriptResult getterSetterKeywordBlock
+ // most general form of subscript declaration; should be kept at the bottom.
+ | subscriptHead subscriptResult codeBlock
+ ;
+subscriptHead : attributes? declarationModifiers? 'subscript' parameterClause  ;
+subscriptResult : '->' attributes? sType  ;
+
+// GRAMMAR OF AN OPERATOR DECLARATION
+
+operatorDeclaration : prefixOperatorDeclaration | postfixOperatorDeclaration | infixOperatorDeclaration  ;
+prefixOperatorDeclaration : 'prefix' 'operator' operator '{' '}'  ;
+postfixOperatorDeclaration : 'postfix' 'operator' operator '{' '}'  ;
+infixOperatorDeclaration : 'infix' 'operator' operator '{' infixOperatorAttributes '}'  ;
+// Order of clauses can be reversed, not indicated in Swift Language Reference
+infixOperatorAttributes : precedenceClause? associativityClause? | associativityClause? precedenceClause? ;
+precedenceClause : 'precedence' precedenceLevel  ;
+precedenceLevel : integerLiteral ;
+associativityClause : 'associativity' associativity  ;
+associativity : 'left' | 'right' | 'none'  ;
+
+// Patterns
+
+
+// GRAMMAR OF A PATTERN
+
+pattern
+ : wildcardPattern typeAnnotation?
+ | identifierPattern typeAnnotation?
+ | valueBindingPattern
+ | tuplePattern typeAnnotation?
+ | enumCasePattern
+ | 'is' sType
+ | pattern 'as' sType
+ | expressionPattern
+ ;
+
+// GRAMMAR OF A WILDCARD PATTERN
+
+wildcardPattern : '_'  ;
+
+// GRAMMAR OF AN IDENTIFIER PATTERN
+
+identifierPattern : identifier  ;
+
+// GRAMMAR OF A VALUE_BINDING PATTERN
+
+valueBindingPattern : 'var' pattern | 'let' pattern  ;
+
+// GRAMMAR OF A TUPLE PATTERN
+
+tuplePattern : '(' tuplePatternElementList? ')'  ;
+tuplePatternElementList
+	:	tuplePatternElement (',' tuplePatternElement)*
+	;
+tuplePatternElement : pattern  ;
+
+// GRAMMAR OF AN ENUMERATION CASE PATTERN
+
+// Swift Language Reference has '.' as mandatory
+enumCasePattern : typeIdentifier? '.'? enumCaseName tuplePattern? ;
+
+// GRAMMAR OF A TYPE CASTING PATTERN
+
+typeCastingPattern : isPattern | asPattern  ;
+isPattern : 'is' sType  ;
+asPattern : pattern 'as' sType  ;
+
+// GRAMMAR OF AN EXPRESSION PATTERN
+
+expressionPattern : expression  ;
+
+// Attributes
+
+// GRAMMAR OF AN ATTRIBUTE
+
+attribute : '@' attributeName attributeArgumentClause? ;
+attributeName : identifier ;
+attributeArgumentClause : '('  balancedTokens?  ')'  ;
+attributes : attribute+ ;
+// Swift Language Reference does not have ','
+balancedTokens : balancedToken balancedTokens? ;
+balancedToken
+ : '('  balancedTokens? ')'
+ | '[' balancedTokens? ']'
+ | '{' balancedTokens? '}'
+ | identifier | expression | contextSensitiveKeyword | literal | operator
+ // | Any punctuation except ( ,  ')' , '[' , ']' , { , or }
+ // Punctuation is very ambiguous, interpreting punctuation as defined in www.thepunctuationguide.com
+ | ':' | ';' | ',' | '!' | '<' | '>' | '-' | '\'' | '/' | '...' | '"'
+ ;
+
+// Expressions
+
+// GRAMMAR OF AN EXPRESSION
+
+expressionList : expression (',' expression)* ;
+
+expression : tryOperator? prefixExpression binaryExpression* ;
+
+prefixExpression
+  : prefixOperator? postfixExpression ';'?
+  | inOutExpression
+  ;
+
+/*
+expression
+	:	prefixOperator expression
+    |	inOutExpression
+    |	primaryExpression
+    |	expression binaryOperator expression
+    |	expression assignmentOperator expression
+    |	expression conditionalOperator expression
+    |	expression typeCastingOperator
+    |	expression postfixOperator
+    |	expression parenthesizedExpression trailingClosure?
+	|	expression '.' 'init'
+ 	|	expression '.' DecimalLiteral
+	|	expression '.' identifier genericArgumentClause?
+	|	expression '.' 'self'
+	|	expression '.' 'dynamicType'
+	|	expression '[' expressionList ']'
+	|	expression '!'
+	|	expression '?'
+	;
+*/
+
+// GRAMMAR OF A PREFIX EXPRESSION
+
+inOutExpression : '&' identifier ;
+
+// GRAMMAR OF A TRY EXPRESSION
+
+tryOperator : 'try' ('?' | '!')? ;
+
+// GRAMMAR OF A BINARY EXPRESSION
+
+binaryExpression
+  : binaryOperator prefixExpression
+  | assignmentOperator tryOperator? prefixExpression
+  | conditionalOperator tryOperator? prefixExpression
+  | typeCastingOperator
+  ;
+
+// GRAMMAR OF AN ASSIGNMENT OPERATOR
+
+assignmentOperator : '='  ;
+
+// GRAMMAR OF A CONDITIONAL OPERATOR
+
+conditionalOperator : '?' tryOperator? expression ':' ;
+
+// GRAMMAR OF A TYPE_CASTING OPERATOR
+
+typeCastingOperator
+  : 'is' sType
+  | 'as' '?' sType
+  | 'as' sType
+  | 'as' '!' sType
+  ;
+
+// GRAMMAR OF A PRIMARY EXPRESSION
+
+primaryExpression
+ : (identifier | operator) genericArgumentClause? // operator not mentioned in the Swift Language Reference
+ | literalExpression
+ | selfExpression
+ | superclassExpression
+ | closureExpression
+ | parenthesizedExpression
+ | implicitMemberExpression
+// | implicit_member_expression disallow as ambig with explicit member expr in postfix_expression
+ | wildcardExpression
+ ;
+
+// GRAMMAR OF A LITERAL EXPRESSION
+
+literalExpression
+ : literal
+ | arrayLiteral
+ | dictionaryLiteral
+ | '__FILE__' | '__LINE__' | '__COLUMN__' | '__FUNCTION__'
+ ;
+
+arrayLiteral : '[' arrayLiteralItems? ']'  ;
+arrayLiteralItems : arrayLiteralItem (',' arrayLiteralItem)* ','?  ;
+arrayLiteralItem : expression ;
+dictionaryLiteral : '[' dictionaryLiteralItems ']' | '[' ':' ']'  ;
+dictionaryLiteralItems : dictionaryLiteralItem (',' dictionaryLiteralItem)* ','? ;
+dictionaryLiteralItem : expression ':' expression  ;
+
+// GRAMMAR OF A SELF EXPRESSION
+
+selfExpression
+ : 'self'
+ | 'self' '.' identifier
+ | 'self' '[' expressionList ']'
+ | 'self' '.' 'init'
+ ;
+
+// GRAMMAR OF A SUPERCLASS EXPRESSION
+
+superclassExpression
+  : superclassMethodExpression
+  | superclassSubscriptExpression
+  | superclassInitializerExpression
+  ;
+
+superclassMethodExpression : 'super' '.' identifier  ;
+superclassSubscriptExpression : 'super' '[' expressionList ']'  ;
+superclassInitializerExpression : 'super' '.' 'init'  ;
+
+// GRAMMAR OF A CLOSURE EXPRESSION
+
+// Statements are not optional in the Swift Language Reference
+closureExpression : '{' closureSignature? statements? '}'  ;
+closureSignature
+ : parameterClause functionResult? 'in'
+ | identifierList functionResult? 'in'
+ | captureList parameterClause functionResult? 'in'
+ | captureList identifierList functionResult? 'in'
+ | captureList 'in'
+ ;
+
+captureList : '[' captureListItems ']' ;
+captureListItems: captureListItem (',' captureListItem)? ;
+captureListItem: captureSpecifier? expression ;
+captureSpecifier : 'weak' | 'unowned' | 'unowned(safe)' | 'unowned(unsafe)'  ;
+
+// GRAMMAR OF A IMPLICIT MEMBER EXPRESSION
+
+implicitMemberExpression : '.' identifier  ;
+
+// GRAMMAR OF A PARENTHESIZED EXPRESSION
+
+parenthesizedExpression : '(' expressionElementList? ')'  ;
+expressionElementList : expressionElement (',' expressionElement)*  ;
+expressionElement : expression | identifier ':' expression  ;
+
+// GRAMMAR OF A WILDCARD EXPRESSION
+
+wildcardExpression : '_'  ;
+
+// GRAMMAR OF A POSTFIX EXPRESSION
+
+postfixExpression
+ : primaryExpression                                             # primary
+ | postfixExpression postfixOperator                             # postfixOperation
+ // Function call with closure expression should always be above a lone parenthesized expression to reduce ambiguity
+ | postfixExpression parenthesizedExpression? closureExpression  # functionCallWithClosureExpression
+ | postfixExpression parenthesizedExpression                     # functionCallExpression
+ | postfixExpression '.' 'init'                                  # initializerExpression
+ // TODO: don't allow '_' here in DecimalLiteral:
+ | postfixExpression '.' DecimalLiteral                         # explicitMemberExpression1
+ | postfixExpression '.' identifier genericArgumentClause?     # explicitMemberExpression2
+ | postfixExpression '.' 'self'                                  # postfixSelfExpression
+ | postfixExpression '.' 'dynamicType'                           # dynamicTypeExpression
+ | postfixExpression '[' expressionList ']'                     # subscriptExpression
+ | postfixExpression '!'                                # forcedValueExpression
+ | postfixExpression '?'                                         # optionalChainingExpression
+ ;
+
+// GRAMMAR OF A FUNCTION CALL EXPRESSION
+
+/*
+functionCallExpression
+  : postfixExpression parenthesizedExpression
+  : postfixExpression parenthesizedExpression? trailingClosure
+  ;
+  */
+
+//trailing_closure : closure_expression  ;
+
+//initializer_expression : postfix_expression '.' 'init' ;
+
+/*explicitMemberExpression
+  : postfixExpression '.' DecimalLiteral // TODO: don't allow '_' here in DecimalLiteral
+  | postfixExpression '.' identifier genericArgumentClause?
+  ;
+  */
+
+//postfix_self_expression : postfix_expression '.' 'self' ;
+
+// GRAMMAR OF A DYNAMIC TYPE EXPRESSION
+
+//dynamic_type_expression : postfix_expression '.' 'dynamicType' ;
+
+// GRAMMAR OF A SUBSCRIPT EXPRESSION
+
+//subscript_expression : postfix_expression '[' expression_list ']' ;
+
+// GRAMMAR OF A FORCED_VALUE EXPRESSION
+
+//forced_value_expression : postfix_expression '!' ;
+
+// GRAMMAR OF AN OPTIONAL_CHAINING EXPRESSION
+
+//optional_chaining_expression : postfix_expression '?' ;
+
+// GRAMMAR OF OPERATORS
+
+// split the operators out into the individual tokens as some of those tokens
+// are also referenced individually. For example, type signatures use
+// <...>.
+
+operatorHead: '=' | '<' | '>' | '!' | '*' | '&' | '==' | '?' | '-' | '&&' | '||' | '/' | OperatorHead;
+operatorCharacter: operatorHead | OperatorCharacter;
+
+operator: operatorHead operatorCharacter*
+  | '..' (operatorCharacter)*
+  | '...'
+  ;
+
+// WHITESPACE scariness:
+
+/* http://tinyurl.com/oalzfus
+"If an operator has no whitespace on the left but is followed
+immediately by a dot (.), it is treated as a postfix unary
+operator. As an example, the ++ operator in a++.b is treated as a
+postfix unary operator (a++ . b rather than a ++ .b).  For the
+purposes of these rules, the characters (, [, and { before an
+operator, the characters ), ], and } after an operator, and the
+characters ,, ;, and : are also considered whitespace.
+
+There is one caveat to the rules above. If the ! or ? operator has no
+whitespace on the left, it is treated as a postfix operator,
+regardless of whether it has whitespace on the right. To use the ?
+operator as syntactic sugar for the Optional type, it must not have
+whitespace on the left. To use it in the conditional (? :) operator,
+it must have whitespace around both sides."
+ */
+
+/**
+ "If an operator has whitespace around both sides or around neither side,
+ it is treated as a binary operator. As an example, the + operator in a+b
+  and a + b is treated as a binary operator."
+*/
+binaryOperator : operator ;
+
+/**
+ "If an operator has whitespace on the left side only, it is treated as a
+ prefix unary operator. As an example, the ++ operator in a ++b is treated
+ as a prefix unary operator."
+*/
+prefixOperator : operator  ; // only if space on left but not right
+
+/**
+ "If an operator has whitespace on the right side only, it is treated as a
+ postfix unary operator. As an example, the ++ operator in a++ b is treated
+ as a postfix unary operator."
+ */
+postfixOperator : operator  ;
+
+// Types
+
+// GRAMMAR OF A TYPE
+
+sType
+ : arrayType
+ | dictionaryType
+ | sType 'throws'? '->' sType  // function-type
+ | sType 'rethrows' '->' sType // function-type
+ | typeIdentifier
+ | tupleType
+ | sType '?'  // optional-type
+ | sType '!'  // implicitly-unwrapped-optional-type
+ | protocolCompositionType
+ | sType '.' 'Type' | sType '.' 'Protocol' // metatype
+ ;
+
+arrayType: '[' sType ']' ;
+
+dictionaryType: '[' sType ':' sType ']' ;
+
+optionalType: sType '?' ;
+
+implicitlyUnwrappedOptionalType: sType '!' ;
+
+// GRAMMAR OF A TYPE ANNOTATION
+
+typeAnnotation : ':' attributes? sType  ;
+
+// GRAMMAR OF A TYPE IDENTIFIER
+
+typeIdentifier
+ : typeName genericArgumentClause?
+ | typeName genericArgumentClause? '.' typeIdentifier
+ | 'Self' // Swift Language Reference does not have this
+ ;
+
+typeName : identifier ;
+
+// GRAMMAR OF A TUPLE TYPE
+
+tupleType : '('  tupleTypeBody? ')'  ;
+tupleTypeBody : tupleTypeElementList '...'? ;
+tupleTypeElementList : tupleTypeElement | tupleTypeElement ',' tupleTypeElementList  ;
+tupleTypeElement : attributes? 'inout'? sType | 'inout'? elementName typeAnnotation ;
+elementName : identifier  ;
+
+// GRAMMAR OF A PROTOCOL COMPOSITION TYPE
+
+protocolCompositionType : 'protocol' '<' protocolIdentifierList? '>'  ;
+protocolIdentifierList : protocolIdentifier | protocolIdentifier ',' protocolIdentifierList  ;
+protocolIdentifier : typeIdentifier  ;
+
+// GRAMMAR OF A METATYPE TYPE
+
+metatypeType : sType '.' 'Type' | sType '.' 'Protocol';
+
+// GRAMMAR OF A TYPE INHERITANCE CLAUSE
+
+typeInheritanceClause : ':' classRequirement ',' typeInheritanceList
+ | ':' classRequirement
+ | ':' typeInheritanceList
+ ;
+typeInheritanceList : typeIdentifier (',' typeIdentifier)* ;
+classRequirement: 'class' ;
+
+// ------ Build Configurations (Macros) -------
+
+compilerControlStatement: buildConfigurationStatement | lineControlStatement ;
+buildConfigurationStatement: '#if' buildConfiguration statements? buildConfigurationElseIfClauses? buildConfigurationElseClause? '#endif' ;
+buildConfigurationElseIfClauses: buildConfigurationElseIfClause+ ;
+buildConfigurationElseIfClause: '#elseif' buildConfiguration statements? ;
+buildConfigurationElseClause: '#else' statements? ;
+
+buildConfiguration: platformTestingFunction | identifier | booleanLiteral
+ | '(' buildConfiguration ')'
+ | '!' buildConfiguration
+ | buildConfiguration ('&&' | '||') buildConfiguration
+ ;
+
+platformTestingFunction: 'os' '(' operatingSystem ')' | 'arch' '(' architecture ')' ;
+operatingSystem: 'OSX' | 'iOS' | 'watchOS' | 'tvOS' ;
+architecture: 'i386' | 'x86_64' | 'arm' | 'arm64' ;
+
+lineControlStatement: '#line' (lineNumber fileName)? ;
+lineNumber: integerLiteral ;
+fileName: StringLiteral ;
+
+// ---------- Lexical Structure -----------
+
+BooleanLiteral: 'true' | 'false' ;
+NilLiteral: 'nil' ;
+
+// GRAMMAR OF AN IDENTIFIER
+
+identifier : Identifier | contextSensitiveKeyword ;
+
+keyword : 'convenience' | 'class' | 'deinit' | 'enum' | 'extension' | 'func' | 'import' | 'init' | 'let' | 'protocol' | 'static' | 'struct' | 'subscript' | 'typealias' | 'var' | 'break' | 'case' | 'continue' | 'default' | 'do' | 'else' | 'fallthrough' | 'if' | 'in' | 'for' | 'return' | 'switch' | 'where' | 'while' | 'as' | 'dynamicType' | 'is' | 'super' | 'self' | 'Self' | 'Type' | 'repeat' ;
+
+contextSensitiveKeyword :
+ 'associativity' | 'convenience' | 'dynamic' | 'didSet' | 'final' | 'get' | 'infix' | 'indirect' |
+ 'lazy' | 'left' | 'mutating' | 'none' | 'nonmutating' | 'optional' | 'operator' | 'override' | 'postfix' | 'precedence' |
+ 'prefix' | 'Protocol' | 'required' | 'right' | 'set' | 'Type' | 'unowned' | 'weak' | 'willSet' |
+ 'iOS' | 'iOSApplicationExtension' | 'OSX' | 'OSXApplicationExtension-' | 'watchOS' | 'x86_64' |
+ 'arm' | 'arm64' | 'i386' | 'os' | 'arch'
+ ;
+
+OperatorHead
+  : '/' | '=' | '-' | '+' | '!' | '*' | '%' | '<' | '>' | '&' | '|' | '^' | '~' | '?'
+  | [\u00A1-\u00A7]
+  | [\u00A9\u00AB\u00AC\u00AE]
+  | [\u00B0-\u00B1\u00B6\u00BB\u00BF\u00D7\u00F7]
+  | [\u2016-\u2017\u2020-\u2027]
+  | [\u2030-\u203E]
+  | [\u2041-\u2053]
+  | [\u2055-\u205E]
+  | [\u2190-\u23FF]
+  | [\u2500-\u2775]
+  | [\u2794-\u2BFF]
+  | [\u2E00-\u2E7F]
+  | [\u3001-\u3003]
+  | [\u3008-\u3030]
+  ;
+
+OperatorCharacter
+  : OperatorHead
+  | [\u0300–\u036F]
+  | [\u1DC0–\u1DFF]
+  | [\u20D0–\u20FF]
+  | [\uFE00–\uFE0F]
+  | [\uFE20–\uFE2F]
+  //| [\uE0100–\uE01EF]  ANTLR can't do >16bit char
+  ;
+
+DotOperatorHead
+  : '..'
+  ;
+
+Identifier : IdentifierHead IdentifierCharacters?
+ | '`' IdentifierHead IdentifierCharacters? '`'
+ | ImplicitParameterName
+ ;
+
+identifierList : (identifier | '_') (',' (identifier | '_'))*  ;
+
+fragment IdentifierHead : [a-zA-Z] | '_'
+ | '\u00A8' | '\u00AA' | '\u00AD' | '\u00AF' | [\u00B2-\u00B5] | [\u00B7-\u00BA]
+ | [\u00BC-\u00BE] | [\u00C0-\u00D6] | [\u00D8-\u00F6] | [\u00F8-\u00FF]
+ | [\u0100-\u02FF] | [\u0370-\u167F] | [\u1681-\u180D] | [\u180F-\u1DBF]
+ | [\u1E00-\u1FFF]
+ | [\u200B-\u200D] | [\u202A-\u202E] | [\u203F-\u2040] | '\u2054' | [\u2060-\u206F]
+ | [\u2070-\u20CF] | [\u2100-\u218F] | [\u2460-\u24FF] | [\u2776-\u2793]
+ | [\u2C00-\u2DFF] | [\u2E80-\u2FFF]
+ | [\u3004-\u3007] | [\u3021-\u302F] | [\u3031-\u303F] | [\u3040-\uD7FF]
+ | [\uF900-\uFD3D] | [\uFD40-\uFDCF] | [\uFDF0-\uFE1F] | [\uFE30-\uFE44]
+ | [\uFE47-\uFFFD]
+/*
+ | U+10000–U+1FFFD | U+20000–U+2FFFD | U+30000–U+3FFFD | U+40000–U+4FFFD
+ | U+50000–U+5FFFD | U+60000–U+6FFFD | U+70000–U+7FFFD | U+80000–U+8FFFD
+ | U+90000–U+9FFFD | U+A0000–U+AFFFD | U+B0000–U+BFFFD | U+C0000–U+CFFFD
+ | U+D0000–U+DFFFD or U+E0000–U+EFFFD
+*/
+ ;
+
+fragment IdentifierCharacter : [0-9]
+ | [\u0300-\u036F] | [\u1DC0-\u1DFF] | [\u20D0-\u20FF] | [\uFE20-\uFE2F]
+ | IdentifierHead
+ ;
+
+fragment IdentifierCharacters : IdentifierCharacter+ ;
+
+ImplicitParameterName : '$' DecimalLiteral ; // TODO: don't allow '_' here
+
+// GRAMMAR OF A LITERAL
+
+booleanLiteral: BooleanLiteral ;
+literal : numericLiteral | StringLiteral | BooleanLiteral | NilLiteral ;
+
+// GRAMMAR OF AN INTEGER LITERAL
+
+numericLiteral: '-'? integerLiteral | '-'? FloatingPointLiteral ;
+
+integerLiteral
+ : BinaryLiteral
+ | OctalLiteral
+ | DecimalLiteral
+ | HexadecimalLiteral
+ ;
+
+BinaryLiteral : '0b' BinaryDigit BinaryLiteralCharacters? ;
+fragment BinaryDigit : [01] ;
+fragment BinaryLiteralCharacter : BinaryDigit | '_'  ;
+fragment BinaryLiteralCharacters : BinaryLiteralCharacter BinaryLiteralCharacters? ;
+
+OctalLiteral : '0o' OctalDigit OctalLiteralCharacters? ;
+fragment OctalDigit : [0-7] ;
+fragment OctalLiteralCharacter : OctalDigit | '_'  ;
+fragment OctalLiteralCharacters : OctalLiteralCharacter+ ;
+
+DecimalLiteral : DecimalDigit DecimalLiteralCharacters? ;
+fragment DecimalDigit : [0-9] ;
+fragment DecimalDigits : DecimalDigit+ ;
+fragment DecimalLiteralCharacter : DecimalDigit | '_'  ;
+fragment DecimalLiteralCharacters : DecimalLiteralCharacter+ ;
+HexadecimalLiteral : '0x' HexadecimalDigit HexadecimalLiteralCharacters? ;
+fragment HexadecimalDigit : [0-9a-fA-F] ;
+fragment HexadecimalLiteralCharacter : HexadecimalDigit | '_'  ;
+fragment HexadecimalLiteralCharacters : HexadecimalLiteralCharacter+ ;
+
+// GRAMMAR OF A FLOATING_POINT LITERAL
+
+FloatingPointLiteral
+ : DecimalLiteral DecimalFraction? DecimalExponent?
+ | HexadecimalLiteral HexadecimalFraction? HexadecimalExponent
+ ;
+fragment DecimalFraction : '.' DecimalLiteral ;
+fragment DecimalExponent : FloatingPointE Sign? DecimalLiteral ;
+fragment HexadecimalFraction : '.' HexadecimalLiteral? ;
+fragment HexadecimalExponent : FloatingPointP Sign? HexadecimalLiteral ;
+fragment FloatingPointE : [eE] ;
+fragment FloatingPointP : [pP] ;
+fragment Sign : [+\-] ;
+
+VersionLiteral: DecimalLiteral DecimalFraction DecimalFraction ;
+
+// GRAMMAR OF A STRING LITERAL
+
+StringLiteral : '"' QuotedText? '"' ;
+fragment QuotedText : QuotedTextItem QuotedText? ;
+fragment QuotedTextItem : EscapedCharacter
+// | '\\(' expression ')'
+ | ~["\\\u000A\u000D]
+ ;
+EscapedCharacter : '\\' [0\\(tnr"']
+ | '\\x' HexadecimalDigit HexadecimalDigit
+ | '\\u' '{' HexadecimalDigit HexadecimalDigit? HexadecimalDigit? HexadecimalDigit? HexadecimalDigit? HexadecimalDigit? HexadecimalDigit? HexadecimalDigit? '}'
+;
+
+WS : [ \n\r\t\u000B\u000C\u0000] -> channel(HIDDEN) ;
+
+/* Added optional newline character to prevent the whitespace lexer rule from matching newline
+ * at the end of the comment. This affects how blank lines are counted around functions.
+ */
+BlockComment : '/*' (BlockComment|.)*? '*/' '\n'? -> channel(HIDDEN) ; // nesting allow
+
+LineComment : '//' .*? ('\n'|EOF) -> channel(HIDDEN) ;
diff --git a/pmd-swift/src/main/java/net/sourceforge/pmd/cpd/SwiftLanguage.java b/pmd-swift/src/main/java/net/sourceforge/pmd/cpd/SwiftLanguage.java
new file mode 100644
index 0000000000..324c4820a1
--- /dev/null
+++ b/pmd-swift/src/main/java/net/sourceforge/pmd/cpd/SwiftLanguage.java
@@ -0,0 +1,19 @@
+/**
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+package net.sourceforge.pmd.cpd;
+
+import net.sourceforge.pmd.cpd.SwiftTokenizer;
+
+/**
+ * Language implementation for Swift
+ */
+public class SwiftLanguage extends AbstractLanguage {
+
+    /**
+     * Creates a new Swift Language instance.
+     */
+    public SwiftLanguage() {
+        super("Swift", "swift", new SwiftTokenizer(), ".swift");
+    }
+}
diff --git a/pmd-swift/src/main/java/net/sourceforge/pmd/cpd/SwiftTokenizer.java b/pmd-swift/src/main/java/net/sourceforge/pmd/cpd/SwiftTokenizer.java
new file mode 100644
index 0000000000..52f3d7fb3f
--- /dev/null
+++ b/pmd-swift/src/main/java/net/sourceforge/pmd/cpd/SwiftTokenizer.java
@@ -0,0 +1,81 @@
+/**
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+package net.sourceforge.pmd.cpd;
+
+import net.sourceforge.pmd.lang.ast.TokenMgrError;
+import net.sourceforge.pmd.lang.swift.antlr4.SwiftLexer;
+
+import org.antlr.v4.runtime.ANTLRInputStream;
+import org.antlr.v4.runtime.BaseErrorListener;
+import org.antlr.v4.runtime.Lexer;
+import org.antlr.v4.runtime.RecognitionException;
+import org.antlr.v4.runtime.Recognizer;
+import org.antlr.v4.runtime.Token;
+
+/**
+ * The Swift Tokenizer
+ */
+public class SwiftTokenizer implements Tokenizer {
+
+    @Override
+    public void tokenize(SourceCode sourceCode, Tokens tokenEntries) {
+        StringBuilder buffer = sourceCode.getCodeBuffer();
+
+        try {
+            ANTLRInputStream ais = new ANTLRInputStream(buffer.toString());
+            SwiftLexer lexer = new SwiftLexer(ais);
+
+            lexer.removeErrorListeners();
+            lexer.addErrorListener(new ErrorHandler());
+            Token token = lexer.nextToken();
+
+            while (token.getType() != Token.EOF) {
+                if (token.getChannel() != Lexer.HIDDEN) {
+                    TokenEntry tokenEntry =
+                            new TokenEntry(token.getText(), sourceCode.getFileName(), token.getLine());
+
+                    tokenEntries.add(tokenEntry);
+                }
+                token = lexer.nextToken();
+            }
+        } catch (ANTLRSyntaxError err) {
+            // Wrap exceptions of the Swift tokenizer in a TokenMgrError, so they are correctly handled
+            // when CPD is executed with the '--skipLexicalErrors' command line option
+            throw new TokenMgrError(
+                    "Lexical error in file " + sourceCode.getFileName() + " at line " +
+                    err.getLine() + ", column " + err.getColumn() + ".  Encountered: " + err.getMessage(),
+                    TokenMgrError.LEXICAL_ERROR);
+        } finally {
+            tokenEntries.add(TokenEntry.getEOF());
+        }
+    }
+
+    private static class ErrorHandler extends BaseErrorListener {
+        @Override
+        public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line,
+                int charPositionInLine, String msg, RecognitionException ex) {
+            throw new ANTLRSyntaxError(msg, line, charPositionInLine, ex);
+        }
+    }
+
+    private static class ANTLRSyntaxError extends RuntimeException {
+        private static final long serialVersionUID = 1L;
+        private final int line;
+        private final int column;
+
+        public ANTLRSyntaxError (String msg, int line, int column, RecognitionException cause) {
+            super(msg, cause);
+            this.line = line;
+            this.column = column;
+        }
+
+        public int getLine() {
+            return line;
+        }
+
+        public int getColumn() {
+            return column;
+        }
+    }
+}
diff --git a/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/SwiftLanguageModule.java b/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/SwiftLanguageModule.java
new file mode 100644
index 0000000000..365608dfe0
--- /dev/null
+++ b/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/SwiftLanguageModule.java
@@ -0,0 +1,25 @@
+/**
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+package net.sourceforge.pmd.lang.swift;
+
+import net.sourceforge.pmd.lang.BaseLanguageModule;
+
+/**
+ * Language Module for Swift
+ */
+public class SwiftLanguageModule extends BaseLanguageModule {
+
+    /** The name. */
+    public static final String NAME = "Swift";
+    /** The terse name. */
+    public static final String TERSE_NAME = "swift";
+
+    /**
+     * Create a new instance of Swift Language Module.
+     */
+    public SwiftLanguageModule() {
+        super(NAME, null, TERSE_NAME, null, "swift");
+        addVersion("", null, true);
+    }
+}
diff --git a/pmd-swift/src/main/resources/META-INF/services/net.sourceforge.pmd.cpd.Language b/pmd-swift/src/main/resources/META-INF/services/net.sourceforge.pmd.cpd.Language
new file mode 100644
index 0000000000..a5cd852cde
--- /dev/null
+++ b/pmd-swift/src/main/resources/META-INF/services/net.sourceforge.pmd.cpd.Language
@@ -0,0 +1 @@
+net.sourceforge.pmd.cpd.SwiftLanguage
diff --git a/pmd-swift/src/main/resources/META-INF/services/net.sourceforge.pmd.lang.Language b/pmd-swift/src/main/resources/META-INF/services/net.sourceforge.pmd.lang.Language
new file mode 100644
index 0000000000..467577ddb9
--- /dev/null
+++ b/pmd-swift/src/main/resources/META-INF/services/net.sourceforge.pmd.lang.Language
@@ -0,0 +1 @@
+net.sourceforge.pmd.lang.swift.SwiftLanguageModule
diff --git a/pmd-swift/src/site/markdown/index.md b/pmd-swift/src/site/markdown/index.md
new file mode 100644
index 0000000000..ac13d040c0
--- /dev/null
+++ b/pmd-swift/src/site/markdown/index.md
@@ -0,0 +1,3 @@
+# PMD Swift
+
+Only CPD is supported. There are no PMD rules for Swift.
diff --git a/pmd-swift/src/test/java/net/sourceforge/pmd/LanguageVersionTest.java b/pmd-swift/src/test/java/net/sourceforge/pmd/LanguageVersionTest.java
new file mode 100644
index 0000000000..8d125ead81
--- /dev/null
+++ b/pmd-swift/src/test/java/net/sourceforge/pmd/LanguageVersionTest.java
@@ -0,0 +1,27 @@
+/**
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+package net.sourceforge.pmd;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import net.sourceforge.pmd.lang.LanguageRegistry;
+import net.sourceforge.pmd.lang.LanguageVersion;
+import net.sourceforge.pmd.lang.swift.SwiftLanguageModule;
+
+import org.junit.runners.Parameterized.Parameters;
+
+public class LanguageVersionTest extends AbstractLanguageVersionTest {
+
+    public LanguageVersionTest(String name, String terseName, String version, LanguageVersion expected) {
+        super(name, terseName, version, expected);
+    }
+
+    @Parameters
+    public static Collection<Object[]> data() {
+        return Arrays.asList(new Object[][] {
+                { SwiftLanguageModule.NAME, SwiftLanguageModule.TERSE_NAME, "", LanguageRegistry.getLanguage(SwiftLanguageModule.NAME).getDefaultVersion() }
+            });
+    }
+}
diff --git a/pmd-swift/src/test/java/net/sourceforge/pmd/cpd/SwiftTokenizerTest.java b/pmd-swift/src/test/java/net/sourceforge/pmd/cpd/SwiftTokenizerTest.java
new file mode 100644
index 0000000000..059429850b
--- /dev/null
+++ b/pmd-swift/src/test/java/net/sourceforge/pmd/cpd/SwiftTokenizerTest.java
@@ -0,0 +1,37 @@
+/**
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+package net.sourceforge.pmd.cpd;
+
+import java.io.IOException;
+
+import net.sourceforge.pmd.testframework.AbstractTokenizerTest;
+
+import org.apache.commons.io.IOUtils;
+import org.junit.Before;
+import org.junit.Test;
+
+
+public class SwiftTokenizerTest extends AbstractTokenizerTest {
+
+    private static final String FILENAME = "BTree.swift";
+
+    @Before
+    @Override
+    public void buildTokenizer() throws IOException {
+        this.tokenizer = new SwiftTokenizer();
+        this.sourceCode = new SourceCode(new SourceCode.StringCodeLoader(this.getSampleCode(), FILENAME));
+    }
+
+    @Override
+    public String getSampleCode() throws IOException {
+         return IOUtils.toString(SwiftTokenizer.class.getResourceAsStream(FILENAME));
+     }
+
+    @Test
+    public void tokenizeTest() throws IOException {
+        this.expectedTokenCount = 3811;
+        super.tokenizeTest();
+    }
+}
+
diff --git a/pmd-swift/src/test/resources/net/sourceforge/pmd/cpd/BTree.swift b/pmd-swift/src/test/resources/net/sourceforge/pmd/cpd/BTree.swift
new file mode 100644
index 0000000000..96731997ad
--- /dev/null
+++ b/pmd-swift/src/test/resources/net/sourceforge/pmd/cpd/BTree.swift
@@ -0,0 +1,890 @@
+//  Downloaded on 2016/03/02 from https://github.com/lorentey/BTree/blame/master/Sources/BTree.swift
+//
+//  BTree.swift
+//  BTree
+//
+//  Created by Károly Lőrentey on 2016-02-19.
+//  Copyright © 2015–2016 Károly Lőrentey.
+//
+
+/// B-trees are search trees that provide an ordered key-value store with excellent performance characteristics.
+public struct BTree<Key: Comparable, Payload> {
+    public typealias Element = (Key, Payload)
+    internal typealias Node = BTreeNode<Key, Payload>
+
+    internal var root: Node
+
+    internal init(_ root: Node) {
+        self.root = root
+    }
+
+    /// Initialize a new b-tree with no elements.
+    ///
+    /// - Parameter order: The maximum number of children for tree nodes.
+    public init(order: Int = Node.defaultOrder) {
+        self.root = Node(order: order)
+    }
+
+    /// The order of this tree, i.e., the maximum number of children for tree nodes.
+    public var order: Int { return root.order }
+    /// The depth of this tree. Depth starts at 0 for a tree that has a single root node.
+    public var depth: Int { return root.depth }
+}
+
+//MAKE: Uniquing
+
+public extension BTree {
+    internal var isUnique: Bool {
+        mutating get {
+            return isUniquelyReferenced(&root)
+        }
+    }
+
+    internal mutating func makeUnique() {
+        guard !isUnique else { return }
+        root = root.clone()
+    }
+}
+
+//MARK: SequenceType
+
+extension BTree: SequenceType {
+    public typealias Generator = BTreeGenerator<Key, Payload>
+
+    /// Returns true iff this tree has no elements.
+    public var isEmpty: Bool { return root.count == 0 }
+
+    /// Returns a generator over the elements of this b-tree. Elements are sorted by key.
+    public func generate() -> Generator {
+        return Generator(BTreeStrongPath(root: root, position: 0))
+    }
+
+    /// Returns a generator starting at a specific index.
+    public func generate(from index: Index) -> Generator {
+        index.state.expectRoot(root)
+        return Generator(BTreeStrongPath(root: root, slotsFrom: index.state))
+    }
+
+    /// Returns a generator starting at a specific position.
+    public func generate(fromPosition position: Int) -> Generator {
+        return Generator(BTreeStrongPath(root: root, position: position))
+    }
+
+    /// Returns a generator starting at the element with the specified key.
+    /// If the tree contains no such element, the generator is positioned at the first element with a larger key.
+    /// If there are multiple elements with the same key, `selector` indicates which matching element to find.
+    public func generate(from key: Key, choosing selector: BTreeKeySelector = .Any) -> Generator {
+        return Generator(BTreeStrongPath(root: root, key: key, choosing: selector))
+    }
+
+    /// Call `body` on each element in self in the same order as a for-in loop.
+    public func forEach(@noescape body: (Element) throws -> ()) rethrows {
+        try root.forEach(body)
+    }
+
+    /// A version of `forEach` that allows `body` to interrupt iteration by returning `false`.
+    ///
+    /// - Returns: `true` iff `body` returned true for all elements in the tree.
+    public func forEach(@noescape body: (Element) throws -> Bool) rethrows -> Bool {
+        return try root.forEach(body)
+    }
+}
+
+//MARK: CollectionType
+
+extension BTree: CollectionType {
+    public typealias Index = BTreeIndex<Key, Payload>
+    public typealias SubSequence = BTree<Key, Payload>
+
+    /// The index of the first element of this tree. Elements are sorted by key.
+    ///
+    /// - Complexity: O(log(`count`))
+    public var startIndex: Index {
+        return Index(BTreeWeakPath(startOf: root))
+    }
+
+    /// The index after the last element of this tree. (Equals `startIndex` when the tree is empty.)
+    ///
+    /// - Complexity: O(1)
+    public var endIndex: Index {
+        return Index(BTreeWeakPath(endOf: root))
+    }
+
+    /// The number of elements in this tree.
+    public var count: Int {
+        return root.count
+    }
+
+    /// Returns the element at `index`.
+    ///
+    /// - Complexity: O(1)
+    public subscript(index: Index) -> Element {
+        get {
+            index.state.expectRoot(self.root)
+            return index.state.element
+        }
+    }
+
+    /// Returns a tree consisting of elements in the specified range of indexes.
+    ///
+    /// - Complexity: O(log(`count`))
+    public subscript(range: Range<Index>) -> BTree<Key, Payload> {
+        get {
+            return subtree(with: range)
+        }
+    }
+}
+
+//MARK: Lookups
+
+/// When the tree contains multiple elements with the same key, you can use a key selector to specify
+/// that you want to use the first or last matching element, or that you don't care which element you get.
+/// (The latter is sometimes faster.)
+public enum BTreeKeySelector {
+    /// Look for the first element that matches the key, or insert a new element before existing matches.
+    case First
+    /// Look for the last element that matches the key, or insert a new element after existing matches.
+    case Last
+    /// Look for the first element that has a greater key, or insert a new element after existing matches.
+    case After
+    /// Accept any element that matches the key. This is sometimes faster, because the search may stop before reaching
+    /// a leaf node.
+    case Any
+}
+
+public extension BTree {
+
+    /// Returns the first element in this tree, or `nil` if the tree is empty.
+    ///
+    /// - Complexity: O(log(`count`))
+    public var first: Element? {
+        return root.first
+    }
+
+    /// Returns the last element in this tree, or `nil` if the tree is empty.
+    ///
+    /// - Complexity: O(log(`count`))
+    public var last: Element? {
+        return root.last
+    }
+
+    /// Returns the element at `position`.
+    ///
+    /// - Requires: `position >= 0 && position < count`
+    /// - Complexity: O(log(`count`))
+    @warn_unused_result
+    public func elementAtPosition(position: Int) -> Element {
+        precondition(position >= 0 && position < count)
+        var position = position
+        var node = root
+        while !node.isLeaf {
+            let slot = node.slotOfPosition(position)
+            if slot.match {
+                return node.elements[slot.index]
+            }
+            let child = node.children[slot.index]
+            position -= slot.position - child.count
+            node = child
+        }
+        return node.elements[position]
+    }
+
+    /// Returns the payload of an element of this tree with the specified key, or `nil` if there is no such element.
+    /// If there are multiple elements with the same key, `selector` indicates which matching element to find.
+    ///
+    /// - Complexity: O(log(`count`))
+    @warn_unused_result
+    public func payloadOf(key: Key, choosing selector: BTreeKeySelector = .Any) -> Payload? {
+        switch selector {
+        case .Any:
+            var node = root
+            while true {
+                let slot = node.slotOf(key, choosing: .First)
+                if let m = slot.match {
+                    return node.elements[m].1
+                }
+                if node.isLeaf {
+                    break
+                }
+                node = node.children[slot.descend]
+            }
+            return nil
+        default:
+            var node = root
+            var lastmatch: Payload? = nil
+            while true {
+                let slot = node.slotOf(key, choosing: selector)
+                if let m = slot.match {
+                    lastmatch = node.elements[m].1
+                }
+                if node.isLeaf {
+                    break
+                }
+                node = node.children[slot.descend]
+            }
+            return lastmatch
+        }
+    }
+
+    /// Returns an index to an element in this tree with the specified key, or `nil` if there is no such element.
+    /// If there are multiple elements with the same key, `selector` indicates which matching element to find.
+    ///
+    /// - Complexity: O(log(`count`))
+    @warn_unused_result
+    public func indexOf(key: Key, choosing selector: BTreeKeySelector = .Any) -> Index? {
+        let path = BTreeWeakPath(root: root, key: key, choosing: selector)
+        guard !path.isAtEnd && (selector == .After || path.key == key) else { return nil }
+        return Index(path)
+    }
+
+    /// Returns the position of the first element in this tree with the specified key, or `nil` if there is no such element.
+    /// If there are multiple elements with the same key, `selector` indicates which matching element to find.
+    ///
+    /// - Complexity: O(log(`count`))
+    @warn_unused_result
+    public func positionOf(key: Key, choosing selector: BTreeKeySelector = .Any) -> Int? {
+        var node = root
+        var position = 0
+        var match: Int? = nil
+        while !node.isLeaf {
+            let slot = node.slotOf(key, choosing: selector)
+            let child = node.children[slot.descend]
+            if let m = slot.match {
+                let p = node.positionOfSlot(m)
+                match = position + p
+                position += p - (m == slot.descend ? node.children[m].count : 0)
+            }
+            else {
+                position += node.positionOfSlot(slot.descend) - child.count
+            }
+            node = child
+        }
+        let slot = node.slotOf(key, choosing: selector)
+        if let m = slot.match {
+            return position + m
+        }
+        return match
+    }
+
+    /// Returns the position of the element at `index`.
+    ///
+    /// - Complexity: O(1)
+    @warn_unused_result
+    public func positionOfIndex(index: Index) -> Int {
+        index.state.expectRoot(root)
+        return index.state.position
+    }
+
+    /// Returns the index of the element at `position`.
+    ///
+    /// - Requires: `position >= 0 && position <= count`
+    /// - Complexity: O(log(`count`))
+    @warn_unused_result
+    public func indexOfPosition(position: Int) -> Index {
+        return Index(BTreeWeakPath(root: root, position: position))
+    }
+}
+
+
+//MARK: Editing
+
+extension BTree {
+    /// Edit the tree at a path that is to be discovered on the way down, ensuring that all nodes on the path are 
+    /// uniquely held by this tree. 
+    /// This is a simple (but not easy, alas) interface that allows implementing basic editing operations using 
+    /// recursion without adding a separate method on `BTreeNode` for each operation.
+    ///
+    /// Editing is split into two phases: the descent phase and the ascend phase. 
+    ///
+    /// - During descent, the `descend` closure is called repeatedly to get the next child slot to drill down into.
+    ///   When the closure returns `nil`, the phase stops and the ascend phase begins.
+    /// - During ascend, the `ascend` closure is called for each node for which `descend` returned non-nil, in reverse
+    ///   order.
+    ///
+    /// - Parameter descend: A closure that, when given a node, returns the child slot toward which the editing should
+    ///   continue descending, or `nil` if the descent should stop. The closure may set outside references to the 
+    ///   node it gets, and may modify the node as it likes; however, it shouldn't modify anything in the tree outside
+    ///   the node's subtree, and it should not set outside references to the node's descendants.
+    /// - Parameter ascend: A closure that processes a step of ascending back towards the root. It receives a parent node
+    ///   and the child slot from which this step is ascending. The closure may set outside references to the
+    ///   node it gets, and may modify the subtree as it likes; however, it shouldn't modify anything in the tree outside
+    ///   the node's subtree.
+    internal mutating func edit(@noescape descend descend: Node -> Int?, @noescape ascend: (Node, Int) -> Void) {
+        makeUnique()
+        root.edit(descend: descend, ascend: ascend)
+    }
+}
+
+//MARK: Insertion
+
+extension BTree {
+    /// Insert the specified element into the tree at `position`.
+    ///
+    /// - Requires: The key of the supplied element does not violate the b-tree's ordering requirement.
+    ///   (This is only verified in non-optimized builds.)
+    /// - Note: When you need to perform multiple modifications on the same tree,
+    ///   `BTreeCursor` provides an alternative interface that's often more efficient.
+    /// - Complexity: O(log(`count`))
+    public mutating func insert(element: Element, at position: Int) {
+        precondition(position >= 0 && position <= count)
+        makeUnique()
+        var pos = count - position
+        var splinter: BTreeSplinter<Key, Payload>? = nil
+        var element = element
+        edit(
+            descend: { node in
+                let slot = node.slotOfPosition(node.count - pos)
+                assert(slot.index == 0 || node.elements[slot.index - 1].0 <= element.0)
+                assert(slot.index == node.elements.count || node.elements[slot.index].0 >= element.0)
+                if !slot.match {
+                    // Continue descending.
+                    pos -= node.count - slot.position
+                    return slot.index
+                }
+                if node.isLeaf {
+                    // Found the insertion point. Insert, then start ascending.
+                    node.insert(element, inSlot: slot.index)
+                    if node.isTooLarge {
+                        splinter = node.split()
+                    }
+                    return nil
+                }
+                // For internal nodes, put the new element in place of the old at the same position,
+                // then continue descending toward the next position, inserting the old element.
+                element = node.setElementInSlot(slot.index, to: element)
+                pos = node.children[slot.index + 1].count
+                return slot.index + 1
+            },
+            ascend: { node, slot in
+                node.count += 1
+                if let s = splinter {
+                    node.insert(s, inSlot: slot)
+                    splinter = node.isTooLarge ? node.split() : nil
+                }
+            }
+        )
+        if let s = splinter {
+            root = Node(left: root, separator: s.separator, right: s.node)
+        }
+    }
+
+    /// Set the payload at `position`, and return the payload originally stored there.
+    ///
+    /// - Requires: `position < count`
+    /// - Note: When you need to perform multiple modifications on the same tree,
+    ///   `BTreeCursor` provides an alternative interface that's often more efficient.
+    /// - Complexity: O(log(`count`))
+    public mutating func setPayloadAt(position: Int, to payload: Payload) -> Payload {
+        precondition(position >= 0 && position < count)
+        makeUnique()
+        var pos = count - position
+        var old: Payload? = nil
+        edit(
+            descend: { node in
+                let slot = node.slotOfPosition(node.count - pos)
+                if !slot.match {
+                    // Continue descending.
+                    pos -= node.count - slot.position
+                    return slot.index
+                }
+                old = node.elements[slot.index].1
+                node.elements[slot.index].1 = payload
+                return nil
+            },
+            ascend: { node, slot in
+            }
+        )
+        return old!
+    }
+
+    /// Insert `element` into the tree as a new element.
+    /// If the tree already contains elements with the same key, `selector` specifies where to put the new element.
+    ///
+    /// - Note: When you need to perform multiple modifications on the same tree,
+    ///   `BTreeCursor` provides an alternative interface that's often more efficient.
+    /// - Complexity: O(log(`count`))
+    public mutating func insert(element: Element, at selector: BTreeKeySelector = .Any) {
+        makeUnique()
+        let selector: BTreeKeySelector = (selector == .First ? .First : .After)
+        var splinter: BTreeSplinter<Key, Payload>? = nil
+        edit(
+            descend: { node in
+                let slot = node.slotOf(element.0, choosing: selector)
+                if !node.isLeaf {
+                    return slot.descend
+                }
+                node.insert(element, inSlot: slot.descend)
+                if node.isTooLarge {
+                    splinter = node.split()
+                }
+                return nil
+            },
+            ascend: { node, slot in
+                node.count += 1
+                if let s = splinter {
+                    node.insert(s, inSlot: slot)
+                    splinter = node.isTooLarge ? node.split() : nil
+                }
+            }
+        )
+        if let s = splinter {
+            root = Node(left: root, separator: s.separator, right: s.node)
+        }
+    }
+
+    /// Insert `element` into the tree, replacing an element with the same key if there is one.
+    /// If the tree already contains multiple elements with the same key, `selector` specifies which one to replace.
+    ///
+    /// - Note: When you need to perform multiple modifications on the same tree,
+    ///   `BTreeCursor` provides an alternative interface that's often more efficient.
+    /// - Complexity: O(log(`count`))
+    public mutating func insertOrReplace(element: Element, at selector: BTreeKeySelector = .Any) -> Payload? {
+        let selector = (selector == .After ? .Last : selector)
+        makeUnique()
+        var old: Payload? = nil
+        var match: (node: Node, slot: Int)? = nil
+        var splinter: BTreeSplinter<Key, Payload>? = nil
+        edit(
+            descend: { node in
+                let slot = node.slotOf(element.0, choosing: selector)
+                if node.isLeaf {
+                    if let m = slot.match {
+                        // We found the element we want to replace.
+                        old = node.setElementInSlot(m, to: element).1
+                        match = nil
+                    }
+                    else if old == nil && match == nil {
+                        // The tree contains no matching elements; insert a new one.
+                        node.insert(element, inSlot: slot.descend)
+                        if node.isTooLarge {
+                            splinter = node.split()
+                        }
+                    }
+                    return nil
+                }
+                if let m = slot.match {
+                    if selector == .Any {
+                        // When we don't care about which element to replace, we stop the descent at the first match.
+                        old = node.setElementInSlot(m, to: element).1
+                        return nil
+                    }
+                    // Otherwise remember this match and replace it during ascend if it's the last one.
+                    match = (node, m)
+                }
+                return slot.descend
+            },
+            ascend: { node, slot in
+                if let m = match {
+                    // We're looking for the node that contains the last match.
+                    if m.node === node {
+                        // Found it; replace the matching element and cancel the search.
+                        old = node.setElementInSlot(m.slot, to: element).1
+                        match = nil
+                    }
+                }
+                else if old == nil {
+                    // We're ascending from an insertion.
+                    node.count += 1
+                    if let s = splinter {
+                        node.insert(s, inSlot: slot)
+                        splinter = node.isTooLarge ? node.split() : nil
+                    }
+                }
+            }
+        )
+        if let s = splinter {
+            root = Node(left: root, separator: s.separator, right: s.node)
+        }
+        return old
+    }
+}
+
+//MARK: Removal
+
+extension BTree {
+    /// Remove and return the first element.
+    ///
+    /// - Complexity: O(log(`count`))
+    public mutating func removeFirst() -> Element {
+        return removeAt(0)
+    }
+
+    /// Remove and return the last element.
+    ///
+    /// - Complexity: O(log(`count`))
+    public mutating func removeLast() -> Element {
+        return removeAt(count - 1)
+    }
+
+    /// Remove and return the first element, or return `nil` if the tree is empty.
+    ///
+    /// - Complexity: O(log(`count`))
+    public mutating func popFirst() -> Element? {
+        guard !isEmpty else { return nil }
+        return removeAt(0)
+    }
+
+    /// Remove and return the first element, or return `nil` if the tree is empty.
+    ///
+    /// - Complexity: O(log(`count`))
+    public mutating func popLast() -> Element? {
+        guard !isEmpty else { return nil }
+        return removeAt(count - 1)
+    }
+
+    /// Remove and return the element at the specified position.
+    ///
+    /// - Note: When you need to perform multiple modifications on the same tree,
+    ///   `BTreeCursor` provides an alternative interface that's often more efficient.
+    /// - Complexity: O(log(`count`))
+    public mutating func removeAt(position: Int) -> Element {
+        precondition(position >= 0 && position < count)
+        makeUnique()
+        var pos = count - position
+        var matching: (node: Node, slot: Int)? = nil
+        var old: Element? = nil
+        edit(
+            descend: { node in
+                let slot = node.slotOfPosition(node.count - pos)
+                if !slot.match {
+                    // No match yet; continue descending.
+                    assert(!node.isLeaf)
+                    pos -= node.count - slot.position
+                    return slot.index
+                }
+                if node.isLeaf {
+                    // The position we're looking for is in a leaf node; we can remove it directly.
+                    old = node.removeSlot(slot.index)
+                    return nil
+                }
+                // When the position happens to fall into an internal node, remember the match and continue
+                // removing the next position (which is guaranteed to be in a leaf node).
+                // We'll replace the removed element with this one during the ascend.
+                matching = (node, slot.index)
+                pos = node.children[slot.index + 1].count
+                return slot.index + 1
+            },
+            ascend: { node, slot in
+                node.count -= 1
+                if let m = matching where m.node === node {
+                    // We've removed the element at the next position; put it back in place of the
+                    // element we actually want to remove.
+                    old = node.setElementInSlot(m.slot, to: old!)
+                    matching = nil
+                }
+                if node.children[slot].isTooSmall {
+                    node.fixDeficiency(slot)
+                }
+            }
+        )
+        if root.children.count == 1 {
+            assert(root.elements.count == 0)
+            root = root.children[0]
+        }
+        return old!
+    }
+
+    /// Remove an element with the specified key, if it exists.
+    /// If there are multiple elements with the same key, `selector` indicates which matching element to remove.
+    ///
+    /// - Returns: The removed element, or `nil` if there was no element with `key` in the tree.
+    /// - Note: When you need to perform multiple modifications on the same tree,
+    ///   `BTreeCursor` provides an alternative interface that's often more efficient.
+    /// - Complexity: O(log(`count`))
+    public mutating func remove(key: Key, at selector: BTreeKeySelector = .Any) -> Element? {
+        let selector = (selector == .After ? .Last : selector)
+        makeUnique()
+        var old: Element? = nil
+        var matching: (node: Node, slot: Int)? = nil
+        edit(
+            descend: { node in
+                let slot = node.slotOf(key, choosing: selector)
+                if node.isLeaf {
+                    if let m = slot.match {
+                        old = node.removeSlot(m)
+                        matching = nil
+                    }
+                    else if matching != nil {
+                        old = node.removeSlot(slot.descend == node.elements.count ? slot.descend - 1 : slot.descend)
+                    }
+                    return nil
+                }
+                if let m = slot.match {
+                    matching = (node, m)
+                }
+                return slot.descend
+            },
+            ascend: { node, slot in
+                if let o = old {
+                    node.count -= 1
+                    if let m = matching where m.node === node {
+                        old = node.setElementInSlot(m.slot, to: o)
+                        matching = nil
+                    }
+                    if node.children[slot].isTooSmall {
+                        node.fixDeficiency(slot)
+                    }
+                }
+            }
+        )
+        if root.children.count == 1 {
+            assert(root.elements.count == 0)
+            root = root.children[0]
+        }
+        return old
+    }
+
+    /// Remove and return the element referenced by the given index.
+    ///
+    /// - Complexity: O(log(`count`))
+    public mutating func removeAtIndex(index: Index) -> Element {
+        return withCursorAt(index) { cursor in
+            return cursor.remove()
+        }
+    }
+
+    /// Remove all elements from this tree.
+    public mutating func removeAll() {
+        root = Node(order: root.order)
+    }
+}
+
+//MARK: Subtree extraction
+
+extension BTree {
+    /// Returns a subtree containing the initial `maxLength` elements in this tree.
+    ///
+    /// If `maxLength` exceeds `self.count`, the result contains all the elements of `self`.
+    ///
+    /// - Complexity: O(log(`count`))
+    public func prefix(maxLength: Int) -> BTree {
+        precondition(maxLength >= 0)
+        if maxLength == 0 {
+            return BTree(order: order)
+        }
+        if maxLength >= count {
+            return self
+        }
+        return BTreeStrongPath(root: root, position: maxLength).prefix()
+    }
+
+    /// Returns a subtree containing all but the last `n` elements.
+    ///
+    /// - Complexity: O(log(`count`))
+    public func dropLast(n: Int) -> BTree {
+        precondition(n >= 0)
+        return prefix(max(0, count - n))
+    }
+
+    /// Returns a subtree containing all elements before the specified index.
+    ///
+    /// - Complexity: O(log(`count`))
+    public func prefixUpTo(end: Index) -> BTree {
+        end.state.expectRoot(root)
+        if end.state.isAtEnd {
+            return self
+        }
+        return end.state.prefix()
+    }
+
+    /// Returns a subtree containing all elements whose key is less than `key`.
+    ///
+    /// - Complexity: O(log(`count`))
+    public func prefixUpTo(end: Key) -> BTree {
+        let path = BTreeStrongPath(root: root, key: end, choosing: .First)
+        if path.isAtEnd {
+            return self
+        }
+        return path.prefix()
+    }
+
+    /// Returns a subtree containing all elements at or before the specified index.
+    ///
+    /// - Complexity: O(log(`count`))
+    public func prefixThrough(stop: Index) -> BTree {
+        return prefixUpTo(stop.successor())
+    }
+
+    /// Returns a subtree containing all elements whose key is less than or equal to `key`.
+    ///
+    /// - Complexity: O(log(`count`))
+    public func prefixThrough(stop: Key) -> BTree {
+        let path = BTreeStrongPath(root: root, key: stop, choosing: .After)
+        if path.isAtEnd {
+            return self
+        }
+        return path.prefix()
+    }
+
+    /// Returns a tree containing the final `maxLength` elements in this tree.
+    ///
+    /// If `maxLength` exceeds `self.count`, the result contains all the elements of `self`.
+    ///
+    /// - Complexity: O(log(`count`))
+    public func suffix(maxLength: Int) -> BTree {
+        precondition(maxLength >= 0)
+        if maxLength == 0 {
+            return BTree(order: order)
+        }
+        if maxLength >= count {
+            return self
+        }
+        return BTreeStrongPath(root: root, position: count - maxLength - 1).suffix()
+    }
+
+    /// Returns a subtree containing all but the first `n` elements.
+    ///
+    /// - Complexity: O(log(`count`))
+    public func dropFirst(n: Int) -> BTree {
+        precondition(n >= 0)
+        return suffix(max(0, count - n))
+    }
+
+    /// Returns a subtree containing all elements at or after the specified index.
+    ///
+    /// - Complexity: O(log(`count`))
+    public func suffixFrom(start: Index) -> BTree {
+        start.state.expectRoot(root)
+        if start.state.position == 0 {
+            return self
+        }
+        return start.predecessor().state.suffix()
+    }
+
+    /// Returns a subtree containing all elements whose key is greater than or equal to `key`.
+    ///
+    /// - Complexity: O(log(`count`))
+    public func suffixFrom(start: Key) -> BTree {
+        var path = BTreeStrongPath(root: root, key: start, choosing: .First)
+        if path.isAtStart {
+            return self
+        }
+        path.moveBackward()
+        return path.suffix()
+    }
+
+    /// Return a subtree consisting of elements in the specified range of indexes.
+    ///
+    /// - Complexity: O(log(`count`))
+    @warn_unused_result
+    public func subtree(with range: Range<Index>) -> BTree<Key, Payload> {
+        range.startIndex.state.expectRoot(root)
+        range.endIndex.state.expectRoot(root)
+        let start = range.startIndex.state.position
+        let end = range.endIndex.state.position
+        precondition(0 <= start && start <= end && end <= self.count)
+        if start == end {
+            return BTree(order: self.order)
+        }
+        if start == 0 {
+            return prefixUpTo(range.endIndex)
+        }
+        return suffixFrom(range.startIndex).prefix(end - start)
+    }
+
+    /// Return a subtree consisting of elements in the specified range of positions.
+    ///
+    /// - Complexity: O(log(`count`))
+    @warn_unused_result
+    public func subtree(with positions: Range<Int>) -> BTree<Key, Payload> {
+        precondition(positions.startIndex >= 0 && positions.endIndex <= count)
+        if positions.count == 0 {
+            return BTree(order: order)
+        }
+        return dropFirst(positions.startIndex).prefix(positions.count)
+    }
+
+    /// Return a subtree consisting of all elements with keys greater than or equal to `start` but less than `end`.
+    ///
+    /// - Complexity: O(log(`count`))
+    @warn_unused_result
+    public func subtree(from start: Key, to end: Key) -> BTree<Key, Payload> {
+        precondition(start <= end)
+        return suffixFrom(start).prefixUpTo(end)
+    }
+
+    /// Return a submap consisting of all elements with keys greater than or equal to `start` but less than or equal to `end`.
+    ///
+    /// - Complexity: O(log(`count`))
+    @warn_unused_result
+    public func subtree(from start: Key, through stop: Key) -> BTree<Key, Payload> {
+        precondition(start <= stop)
+        return suffixFrom(start).prefixThrough(stop)
+    }
+}
+
+//MARK: Bulk loading
+
+extension BTree {
+    /// Create a new b-tree from elements of an unsorted sequence, using a stable sort algorithm.
+    ///
+    /// - Parameter elements: An unsorted sequence of arbitrary length.
+    /// - Parameter order: The desired b-tree order. If not specified (recommended), the default order is used.
+    /// - Complexity: O(count * log(`count`))
+    /// - SeeAlso: `init(sortedElements:order:fillFactor:)` for a (faster) variant that can be used if the sequence is already sorted.
+    public init<S: SequenceType where S.Generator.Element == Element>(_ elements: S, dropDuplicates: Bool = false, order: Int = Node.defaultOrder) {
+        self.init(Node(order: order))
+        withCursorAtEnd { cursor in
+            for element in elements {
+                cursor.move(to: element.0, choosing: .Last)
+                let match = !cursor.isAtEnd && cursor.key == element.0
+                if match {
+                    if dropDuplicates {
+                        cursor.element = element
+                    }
+                    else {
+                        cursor.insertAfter(element)
+                    }
+                }
+                else {
+                    cursor.insert(element)
+                }
+            }
+        }
+    }
+
+    /// Create a new b-tree from elements of a sequence sorted by key.
+    ///
+    /// - Parameter sortedElements: A sequence of arbitrary length, sorted by key.
+    /// - Parameter order: The desired b-tree order. If not specified (recommended), the default order is used.
+    /// - Parameter fillFactor: The desired fill factor in each node of the new tree. Must be between 0.5 and 1.0.
+    ///      If not specified, a value of 1.0 is used, i.e., nodes will be loaded with as many elements as possible.
+    /// - Complexity: O(count)
+    /// - SeeAlso: `init(elements:order:fillFactor:)` for a (slower) unsorted variant.
+    public init<S: SequenceType where S.Generator.Element == Element>(sortedElements elements: S, dropDuplicates: Bool = false, order: Int = Node.defaultOrder, fillFactor: Double = 1) {
+        var generator = elements.generate()
+        self.init(order: order, fillFactor: fillFactor, dropDuplicates: dropDuplicates, next: { generator.next() })
+    }
+
+    internal init(order: Int = Node.defaultOrder, fillFactor: Double = 1, dropDuplicates: Bool = false, @noescape next: () -> Element?) {
+        precondition(order > 1)
+        precondition(fillFactor >= 0.5 && fillFactor <= 1)
+        let keysPerNode = Int(fillFactor * Double(order - 1) + 0.5)
+        assert(keysPerNode >= (order - 1) / 2 && keysPerNode <= order - 1)
+
+        var builder = BTreeBuilder<Key, Payload>(order: order, keysPerNode: keysPerNode)
+        if dropDuplicates {
+            guard var buffer = next() else {
+                self.init(Node(order: order))
+                return
+            }
+            while let element = next() {
+                precondition(buffer.0 <= element.0)
+                if buffer.0 < element.0 {
+                    builder.append(buffer)
+                }
+                buffer = element
+            }
+            builder.append(buffer)
+        }
+        else {
+            var lastKey: Key? = nil
+            while let element = next() {
+                precondition(lastKey <= element.0)
+                lastKey = element.0
+                builder.append(element)
+            }
+        }
+        self.init(builder.finish())
+    }
+}
diff --git a/pom.xml b/pom.xml
index 0f3d0c5eab..2fff9cdc86 100644
--- a/pom.xml
+++ b/pom.xml
@@ -893,6 +893,7 @@
         <module>pmd-plsql</module>
         <module>pmd-python</module>
         <module>pmd-ruby</module>
+        <module>pmd-swift</module>
         <module>pmd-test</module>
         <module>pmd-vm</module>
         <module>pmd-xml</module>