[epiphany] Rewrite lineup-parameters in python



commit b98ebd6153f371d56835c3e1f57434ac8e7295d9
Author: Michael Catanzaro <mcatanzaro igalia com>
Date:   Sun Jun 30 17:22:50 2019 -0500

    Rewrite lineup-parameters in python
    
    This is much simpler since it removes the need to manually copy the
    lineup-parameters binary from the build directory into the source
    directory.

 data/lineup-parameters   | 210 +++++++++++++++++++++
 data/lineup-parameters.c | 483 -----------------------------------------------
 data/meson.build         |   9 -
 data/run-uncrustify      |  15 +-
 4 files changed, 216 insertions(+), 501 deletions(-)
---
diff --git a/data/lineup-parameters b/data/lineup-parameters
new file mode 100755
index 000000000..4bfc39194
--- /dev/null
+++ b/data/lineup-parameters
@@ -0,0 +1,210 @@
+#!/usr/bin/env python3
+#
+# Copyright © 2019 Michael Catanzaro <mcatanzaro gnome org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Based on original C lineup-parameters by Sébastien Wilmet <swilmet gnome org>
+# Rewritten in Python to allow simple execution from source directory.
+#
+# Usage: lineup-parameters [file]
+# If the file is not given, stdin is read.
+# The result is printed to stdout.
+#
+# The restrictions:
+# - The function name must be at column 0, followed by a space and an opening
+#   parenthesis;
+# - One parameter per line;
+# - A parameter must follow certain rules (see the regex in the code), but it
+#   doesn't accept all possibilities of the C language.
+# - The opening curly brace ("{") of the function must also be at column 0.
+#
+# If one restriction is missing, the function declaration is not modified.
+#
+# Example:
+#
+# gboolean
+# frobnitz (Frobnitz *frobnitz,
+#           gint magic_number,
+#           GError **error)
+# {
+#   ...
+# }
+#
+# Becomes:
+#
+# gboolean
+# frobnitz (Frobnitz  *frobnitz,
+#           gint       magic_number,
+#           GError   **error)
+# {
+#   ...
+# }
+#
+# TODO: support "..." vararg parameter
+
+import argparse
+import re
+import sys
+
+from typing import NamedTuple
+
+# https://regexr.com/ is your friend.
+functionNameRegex = re.compile(r'^(\w+) ?\(')
+parameterRegex = re.compile(
+    r'^\s*(?P<type>(const\s+)?\w+)'
+    r'\s+(?P<stars>\**)'
+    r'\s*(?P<name>\w+)'
+    r'\s*(?P<end>,|\))'
+    r'\s*$')
+openingCurlyBraceRegex = re.compile(r'^{\s*$')
+
+
+def matchFunctionName(line):
+    match = functionNameRegex.match(line)
+    if match:
+        functionName = match.group(1)
+        firstParamPosition = match.end(0)
+        return (functionName, firstParamPosition)
+    return (None, 0)
+
+
+class ParameterInfo(NamedTuple):
+    paramType: str
+    name: str
+    numStars: int
+    isLastParameter: bool
+
+
+def matchParameter(line):
+    _, firstParamPosition = matchFunctionName(line)
+    match = parameterRegex.match(line[firstParamPosition:])
+    if match is None:
+        return None
+    paramType = match.group('type')
+    assert(paramType is not None)
+    name = match.group('name')
+    assert(name is not None)
+    stars = match.group('stars')
+    numStars = len(stars) if stars is not None else 0
+    end = match.group('end')
+    isLastParameter = True if end is not None and end is ')' else False
+    return ParameterInfo(paramType, name, numStars, isLastParameter)
+
+
+def matchOpeningCurlyBrace(line):
+    return True if openingCurlyBraceRegex.match(line) is not None else False
+
+
+# Length returned is number of lines the declaration takes up
+def getFunctionDeclarationLength(remainingLines):
+    for i in range(len(remainingLines)):
+        currentLine = remainingLines[i]
+        parameterInfo = matchParameter(currentLine)
+        if parameterInfo is None:
+            return 0
+        if parameterInfo.isLastParameter:
+            if i + 1 == len(remainingLines):
+                return 0
+            nextLine = remainingLines[i + 1]
+            if not matchOpeningCurlyBrace(nextLine):
+                return 0
+            return i + 1
+    return 0
+
+
+def getParameterInfos(remainingLines, length):
+    parameterInfos = []
+    for i in range(length):
+        parameterInfos.append(matchParameter(remainingLines[i]))
+    return parameterInfos
+
+
+def computeSpacing(parameterInfos):
+    maxTypeLength = 0
+    maxStarsLength = 0
+    for parameterInfo in parameterInfos:
+        maxTypeLength = max(maxTypeLength, len(parameterInfo.paramType))
+        maxStarsLength = max(maxStarsLength, parameterInfo.numStars)
+    return (maxTypeLength, maxStarsLength)
+
+
+def printParameter(parameterInfo, maxTypeLength, maxStarsLength, outfile):
+    outfile.write(f'{parameterInfo.paramType:<{maxTypeLength + 1}}')
+    paramNamePaddedWithStars = f'{parameterInfo.name:*>{parameterInfo.numStars + len(parameterInfo.name)}}'
+    outfile.write(f'{paramNamePaddedWithStars:>{maxStarsLength + len(parameterInfo.name)}}')
+
+
+def printFunctionDeclaration(remainingLines, length, useTabs, outfile):
+    functionName, _ = matchFunctionName(remainingLines[0])
+    assert(functionName is not None)
+    outfile.write(f'{functionName} (')
+    numSpacesToParenthesis = len(functionName) + 2
+    whitespace = ''
+    if useTabs:
+        tabs = ''.ljust(numSpacesToParenthesis // 8, '\t')
+        spaces = ''.ljust(numSpacesToParenthesis % 8)
+        whitespace = tabs + spaces
+    else:
+        whitespace = ''.ljust(numSpacesToParenthesis)
+    parameterInfos = getParameterInfos(remainingLines, length)
+    maxTypeLength, maxStarsLength = computeSpacing(parameterInfos)
+    numParameters = len(parameterInfos)
+    for i in range(numParameters):
+        parameterInfo = parameterInfos[i]
+        if i != 0:
+            outfile.write(whitespace)
+        printParameter(parameterInfo, maxTypeLength, maxStarsLength, outfile)
+        if i + 1 != numParameters:
+            outfile.write(',\n')
+    outfile.write(')\n')
+
+
+def parseContents(infile, useTabs, outfile):
+    lines = infile.readlines()
+    i = 0
+    while i < len(lines):
+        line = lines[i]
+        functionName, _ = matchFunctionName(line)
+        if functionName is None:
+            outfile.write(line)
+            i += 1
+            continue
+        remainingLines = lines[i:]
+        length = getFunctionDeclarationLength(remainingLines)
+        if length == 0:
+            outfile.write(line)
+            i += 1
+            continue
+        printFunctionDeclaration(remainingLines, length, useTabs, outfile)
+        i += length
+
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser(
+        description='Line up parameters of C functions')
+    parser.add_argument('infile', nargs='?',
+                        type=argparse.FileType('r'),
+                        default=sys.stdin,
+                        help='input C source file')
+    parser.add_argument('-o', metavar='outfile', nargs='?',
+                        type=argparse.FileType('w'),
+                        default=sys.stdout,
+                        help='where to output modified file')
+    parser.add_argument('--tabs', action='store_true',
+                        help='whether use tab characters in the output')
+    args = parser.parse_args()
+    parseContents(args.infile, args.tabs, args.o)
+    args.infile.close()
+    args.o.close()
diff --git a/data/meson.build b/data/meson.build
index 379222988..2d7a6cedd 100644
--- a/data/meson.build
+++ b/data/meson.build
@@ -140,12 +140,3 @@ if appstream_util.found()
     ]
   )
 endif
-
-line_up_parameters = executable(
-  'lineup-parameters',
-  'lineup-parameters.c',
-  dependencies: [
-    gio_dep,
-    gio_unix_dep,
-  ]
-)
diff --git a/data/run-uncrustify b/data/run-uncrustify
index 59ef7da09..c4105f1e6 100755
--- a/data/run-uncrustify
+++ b/data/run-uncrustify
@@ -1,30 +1,27 @@
 #!/bin/bash
 
-DATA=$(dirname "$BASH_SOURCE")
-UNCRUSTIFY=$(command -v uncrustify)
+SOURCE_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )"
 
+UNCRUSTIFY=$(command -v uncrustify)
 if [ -z "$UNCRUSTIFY" ];
 then
     echo "Uncrustify is not installed on your system."
     exit 1
 fi
 
-LINEUP_PARAMETERS="$DATA/../build/data/lineup-parameters"
-
+LINEUP_PARAMETERS="$SOURCE_ROOT/data/lineup-parameters"
 if [ ! -x "$LINEUP_PARAMETERS" ];
 then
-    echo "Script lineup-parameters does not exists here in (source directory)/data, probably because 
Epiphany was built in a different directory than the source directory.
-Copy the program in the (build directory)/data/lineup-parameters here in (source directory)/data and run 
again run-uncrustify.sh."
+    echo "lineup-parameters script is missing"
     exit 1
 fi
 
-
-for DIR in ../embed ../lib ../src ../tests
+for DIR in $SOURCE_ROOT/embed $SOURCE_ROOT/lib $SOURCE_ROOT/src $SOURCE_ROOT/tests
 do
    # Aligning prototypes is not working yet, so avoid headers
    for FILE in $(find "$DIR" -name "*.c" ! -path "*/contrib/*")
     do
-        "$UNCRUSTIFY" -c "$DATA/kr-gnome-indent.cfg" --no-backup "$FILE"
+        "$UNCRUSTIFY" -c "$SOURCE_ROOT/data/kr-gnome-indent.cfg" --no-backup "$FILE"
         "$LINEUP_PARAMETERS" "$FILE" > "$FILE.temp" && mv "$FILE.temp" "$FILE"
    done
 done


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]