prepare-ChangeLog needs to know how to parse Swift files.
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 4 Sep 2015 17:43:19 +0000 (17:43 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 4 Sep 2015 17:43:19 +0000 (17:43 +0000)
https://bugs.webkit.org/show_bug.cgi?id=148784
<rdar://problem/22510062>

Patch by Jason Marcell <jmarcell@apple.com> on 2015-09-04
Reviewed by Darin Adler.

* Scripts/prepare-ChangeLog:
(get_function_line_ranges): Added entry for get_function_line_ranges_for_swift.
(get_function_line_ranges_for_swift): Added function that knows how to parse Swift code.
(parseSwiftFunctionArgs): Added function that knows how to parse Swift function arguments.
* Scripts/webkitperl/prepare-ChangeLog_unittest/parser_unittests.pl: Added.
* Scripts/webkitperl/prepare-ChangeLog_unittest/resources/swift_unittests-expected.txt: Ditto.
* Scripts/webkitperl/prepare-ChangeLog_unittest/resources/swift_unittests.swift: Ditto.
(freeFunction): Ditto.
(MyClass.function): Ditto.
(MyClass.functionWithArgument(_:)): Ditto.
(MyClass.functionWithMoreArguments(_:arg2:)): Ditto.
(MyClass.functionWithNamedFirstArgument(argument:)): Ditto.
(MyClass.functionWithNamedFirstAndSecondArgument(first:second:)): Ditto.
(MyClass.classFunction): Ditto.
(MyClass.readWriteComputedVariable): Ditto.
(MyClass.readOnlyComputedVariable): Ditto.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@189355 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Tools/ChangeLog
Tools/Scripts/prepare-ChangeLog
Tools/Scripts/webkitperl/prepare-ChangeLog_unittest/parser_unittests.pl
Tools/Scripts/webkitperl/prepare-ChangeLog_unittest/resources/swift_unittests-expected.txt [new file with mode: 0644]
Tools/Scripts/webkitperl/prepare-ChangeLog_unittest/resources/swift_unittests.swift [new file with mode: 0644]

index 36f5d76..2a7821a 100644 (file)
@@ -1,3 +1,28 @@
+2015-09-04  Jason Marcell  <jmarcell@apple.com>
+
+        prepare-ChangeLog needs to know how to parse Swift files.
+        https://bugs.webkit.org/show_bug.cgi?id=148784
+        <rdar://problem/22510062>
+
+        Reviewed by Darin Adler.
+
+        * Scripts/prepare-ChangeLog:
+        (get_function_line_ranges): Added entry for get_function_line_ranges_for_swift.
+        (get_function_line_ranges_for_swift): Added function that knows how to parse Swift code.
+        (parseSwiftFunctionArgs): Added function that knows how to parse Swift function arguments.
+        * Scripts/webkitperl/prepare-ChangeLog_unittest/parser_unittests.pl: Added.
+        * Scripts/webkitperl/prepare-ChangeLog_unittest/resources/swift_unittests-expected.txt: Ditto.
+        * Scripts/webkitperl/prepare-ChangeLog_unittest/resources/swift_unittests.swift: Ditto.
+        (freeFunction): Ditto.
+        (MyClass.function): Ditto.
+        (MyClass.functionWithArgument(_:)): Ditto.
+        (MyClass.functionWithMoreArguments(_:arg2:)): Ditto.
+        (MyClass.functionWithNamedFirstArgument(argument:)): Ditto.
+        (MyClass.functionWithNamedFirstAndSecondArgument(first:second:)): Ditto.
+        (MyClass.classFunction): Ditto.
+        (MyClass.readWriteComputedVariable): Ditto.
+        (MyClass.readOnlyComputedVariable): Ditto.
+
 2015-09-04  Ryosuke Niwa  <rniwa@webkit.org>
 
         Import css/css-color-3
index 641ac83..b3a44c6 100755 (executable)
@@ -92,6 +92,8 @@ sub get_function_line_ranges_for_java($$);
 sub get_function_line_ranges_for_javascript($$);
 sub get_function_line_ranges_for_perl($$);
 sub get_selector_line_ranges_for_css($$);
+sub get_function_line_ranges_for_swift($$);
+sub parseSwiftFunctionArgs($);
 sub isAddedStatus($);
 sub isConflictStatus($$$);
 sub isModifiedStatus($);
@@ -639,6 +641,7 @@ sub get_function_line_ranges($$)
     return get_selector_line_ranges_for_css($file_handle, $file_name) if $file_name =~ /\.css$/;
     return get_function_line_ranges_for_perl($file_handle, $file_name) if $file_name =~ /\.p[lm]$/;
     return get_function_line_ranges_for_python($file_handle, $file_name) if $file_name =~ /\.py$/ or $file_name =~ /master\.cfg$/;
+    return get_function_line_ranges_for_swift($file_handle, $file_name) if $file_name =~ /\.swift$/;
 
     # Try to determine the source language based on the script interpreter.
 
@@ -1720,6 +1723,80 @@ sub get_selector_line_ranges_for_css($$)
     return @ranges;
 }
 
+# Read a file and get all the line ranges of the things that look like Swift classes, methods,
+# or functions.
+#
+# Result is a list of triples: [ start_line, end_line, function ].
+
+sub get_function_line_ranges_for_swift($$)
+{
+    my ($fileHandle, $fileName) = @_;
+
+    my @ranges;
+
+    my $currentFunction = "";
+    my $currentClass = "";
+    my $functionStart = 0;
+    my $classStart = 0;
+    my $functionScopeDepth = 0;
+    my $classScopeDepth = 0;
+    my $scopeDepth = 0;
+
+    while (<$fileHandle>) {
+        chomp;
+        next if (/^\s*\/\/.*/);
+        if (/func\s+([\w_][\w\d_]*)\((.*)\)/ || /var\s+([\w_][\w\d_]*):\s+/) {
+            $functionScopeDepth = $scopeDepth;
+            $currentFunction = $1;
+            if ($2) {
+                $currentFunction = "$currentFunction(". parseSwiftFunctionArgs($2) . ")";
+            }
+            if ($currentClass) {
+                $currentFunction = "$currentClass.$currentFunction";
+            }
+            $functionStart = $.;
+        } elsif (/class\s+([\w_][\w\d_]*)/) {
+            $classScopeDepth = $scopeDepth;
+            $currentClass = $1;
+            $classStart = $.;
+        }
+        if (index($_, "{") > -1) {
+            $scopeDepth++;
+        }
+        if (index($_, "}") > -1) {
+            $scopeDepth--;
+        }
+        if ($scopeDepth == $functionScopeDepth) {
+            next unless $functionStart;
+            push(@ranges, [$functionStart, $., $currentFunction]);
+            $currentFunction = "";
+            $functionStart = 0;
+        } elsif ($scopeDepth == $classScopeDepth) {
+            next unless $classStart;
+            $currentClass = "";
+            $classStart = 0;
+        }
+    }
+
+    return @ranges;
+}
+
+sub parseSwiftFunctionArgs($)
+{
+    my ($functionArgs) = @_;
+    my @words = split /, /, $functionArgs;
+    my $argCount = scalar(@words);
+    if ($argCount == 0) {
+        return "";
+    } elsif ($argCount > 0) {
+        # If the first argument is unnamed, give it the name "_"
+        $words[0] =~ s/^(\w+: .*)/_ $1/;
+        return join("", map { $_ =~ s/^(\w+).*/$1/; "$_:" } @words);
+    } else {
+        warn "Unknown argument count.\n";
+    }
+}
+
 sub processPaths(\@)
 {
     my ($paths) = @_;
index df29d47..069abbe 100644 (file)
@@ -43,6 +43,7 @@ my %testFiles = ("perl_unittests.pl" => "get_function_line_ranges_for_perl",
                  "javascript_unittests.js" => "get_function_line_ranges_for_javascript",
                  "css_unittests.css" => "get_selector_line_ranges_for_css",
                  "css_unittests_warning.css" => "get_selector_line_ranges_for_css",
+                 "swift_unittests.swift" => "get_function_line_ranges_for_swift",
                 );
 
 my $resetResults;
diff --git a/Tools/Scripts/webkitperl/prepare-ChangeLog_unittest/resources/swift_unittests-expected.txt b/Tools/Scripts/webkitperl/prepare-ChangeLog_unittest/resources/swift_unittests-expected.txt
new file mode 100644 (file)
index 0000000..a7fb7b8
--- /dev/null
@@ -0,0 +1,51 @@
+{
+  'stderr' => '',
+  'stdout' => '',
+  'ranges' => [
+    [
+      '4',
+      '5',
+      'freeFunction'
+    ],
+    [
+      '11',
+      '12',
+      'MyClass.function'
+    ],
+    [
+      '18',
+      '19',
+      'MyClass.functionWithArgument(_:)'
+    ],
+    [
+      '24',
+      '25',
+      'MyClass.functionWithMoreArguments(_:arg2:)'
+    ],
+    [
+      '31',
+      '32',
+      'MyClass.functionWithNamedFirstArgument(argument:)'
+    ],
+    [
+      '37',
+      '38',
+      'MyClass.functionWithNamedFirstAndSecondArgument(first:second:)'
+    ],
+    [
+      '45',
+      '46',
+      'MyClass.classFunction'
+    ],
+        [
+      '51',
+      '56',
+      'MyClass.readWriteComputedVariable'
+    ],
+    [
+      '59',
+      '61',
+      'MyClass.readOnlyComputedVariable'
+    ],
+  ]
+}
diff --git a/Tools/Scripts/webkitperl/prepare-ChangeLog_unittest/resources/swift_unittests.swift b/Tools/Scripts/webkitperl/prepare-ChangeLog_unittest/resources/swift_unittests.swift
new file mode 100644 (file)
index 0000000..3640e48
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2015 Apple Inc.  All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+// There are other form of function, but I just illustrate them in the class below.
+// `freeFunction()`
+func freeFunction() {
+}
+
+// May also be `struct`, `enum`, `extension`, or `protocol`.
+class MyClass {
+
+    // `MyClass.function()`
+    func function() {
+    }
+
+    // By default the first argument to functions is unnamed, so in Swift you'd call this
+    // as functionWithArgument(foo).
+    //
+    // `MyClass.functionWithArgument(_:)`
+    func functionWithArgument(arg: Arg) {
+    }
+
+    // Second arguments do get a name.
+    //
+    // `MyClass.functionWithMoreArguments(_:arg2:)
+    func functionWithMoreArguments(arg1: Arg, arg2: Arg) {
+    }
+
+    // You can give the first argument a name by specifying an explicit external name.
+    // This would be called as functionWithNamedFirstArgument(argument: 1)
+    //
+    // `MyClass.functionWithNamedFirstArgument(argument:)`
+    func functionWithNamedFirstArgument(argument arg: Arg) {
+    }
+
+    // You can also give a different external name to other arguments as so.
+    //
+    // `MyClass.functionWithNamedFirstAndSecondArgument(first:second:)`
+    func functionWithNamedFirstAndSecondArgument(first arg1: Arg, second arg2: Arg) {
+    }
+
+    // Now for some things I don't know how to specify but can give random suggestions for…
+
+    // I've not seen clever ways of differentiating class functions from instance functions :(
+    //
+    // `MyClass.classFunction()`
+    class func classFunction() {
+    }
+
+    // These map to what would be -computedVariable and -setComputedVariable: in Objective-C.
+    // To make things fun computed variables can also exist outside of a class definition, so
+    // I think they should still be prefixed.
+    var readWriteComputedVariable: Var {
+        // `MyClass.readWriteComputedVariable { get }`
+        get { return 0 }
+        // `MyClass.readWriteComputedVariable { set }`
+        set { print(newValue) }
+    }
+
+    // `MyClass.readOnlyComputedVariable { get }`
+    var readOnlyComputedVariable: Var {
+        return 0
+    }
+
+}
+
+// Swift functions also support type overloading. Traditionally we don't include types in
+// the ChangeLogs for Objective-C, but I assume this can come up in C++ code so I'd suggest
+// doing whatever we do there. That said, overloading is only supported in pure Swift,
+// which I don't anticipate needing to worry about for a while longer.
\ No newline at end of file