Package net.minecraftforge.gradle.extrastuff

Source Code of net.minecraftforge.gradle.extrastuff.FFPatcher

package net.minecraftforge.gradle.extrastuff;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import net.minecraftforge.gradle.StringUtils;
import net.minecraftforge.gradle.common.Constants;

import com.google.code.regexp.Matcher;
import com.google.code.regexp.Pattern;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;

public class FFPatcher
{
    static final String MODIFIERS = "public|protected|private|static|abstract|final|native|synchronized|transient|volatile|strictfp";

    private static final Pattern SYNTHETICS = Pattern.compile("(?m)(\\s*// \\$FF: (synthetic|bridge) method(\\r\\n|\\n|\\r)){1,2}\\s*(?<modifiers>(?:(?:" + MODIFIERS + ") )*)(?<return>.+?) (?<method>.+?)\\((?<arguments>.*)\\)\\s*\\{(\\r\\n|\\n|\\r)\\s*return this\\.(?<method2>.+?)\\((?<arguments2>.*)\\);(\\r\\n|\\n|\\r)\\s*\\}");
    //private static final Pattern TYPECAST = Pattern.compile("\\([\\w\\.]+\\)");

    // Remove TRAILING whitespace
    private static final String TRAILING = "(?m)[ \\t]+$";

    //Remove repeated blank lines
    private static final String NEWLINES = "(?m)^(\\r\\n|\\r|\\n){2,}";
    private static final String EMPTY_SUPER = "(?m)^[ \t]+super\\(\\);(\\r\\n|\\n|\\r)";

    // strip TRAILING 0 from doubles and floats to fix decompile differences on OSX
    // 0.0010D => 0.001D
    // value, type
    private static final String TRAILINGZERO = "([0-9]+\\.[0-9]*[1-9])0+([DdFfEe])";
   
    // new regexes
    private static final String CLASS_REGEX = "(?<modifiers>(?:(?:" + MODIFIERS + ") )*)(?<type>enum|class|interface) (?<name>[\\w$]+)(?: (extends|implements) (?:[\\w$.]+(?:, [\\w$.]+)*))* \\{";
    private static final String ENUM_ENTRY_REGEX = "(?<name>[\\w$]+)\\(\"(?:[\\w$]+)\", [0-9]+(?:, (?<body>.*?))?\\)(?<end> *(?:;|,|\\{)$)";
    private static final String CONSTRUCTOR_REGEX = "(?<modifiers>(?:(?:" + MODIFIERS + ") )*)%s\\((?<parameters>.*?)\\)(?<end>(?: throws (?<throws>[\\w$.]+(?:, [\\w$.]+)*))? *(?:\\{\\}| \\{))";
    private static final String CONSTRUCTOR_CALL_REGEX = "(?<name>this|super)\\((?<body>.*?)\\)(?<end>;)";
    private static final String VALUE_FIELD_REGEX = "private static final %s\\[\\] [$\\w\\d]+ = new %s\\[\\]\\{.*?\\};";

    public static String processFile(String fileName, String text) throws IOException
    {
        StringBuffer out = new StringBuffer();
        Matcher m = SYNTHETICS.matcher(text);
        while(m.find())
        {
            m.appendReplacement(out, synthetic_replacement(m).replace("$", "\\$"));
        }
        m.appendTail(out);
        text = out.toString();

        text = text.replaceAll(TRAILING, "");
       
        text = text.replaceAll(TRAILINGZERO, "$1$2");
       
        List<String> lines = new ArrayList<String>();
        lines.addAll(StringUtils.lines(text));

        processClass(lines, "", 0, "", ""); // mutates the list
        text = Joiner.on(Constants.NEWLINE).join(lines);

        text = text.replaceAll(NEWLINES, Constants.NEWLINE);
        text = text.replaceAll(EMPTY_SUPER, "");
       
        return text;
    }
   
    private static int processClass(List<String> lines, String indent, int startIndex, String qualifiedName, String simpleName)
    {
        Pattern classPattern = Pattern.compile(indent + CLASS_REGEX);
       
        for (int i = startIndex; i < lines.size(); i++)
        {
            String line = lines.get(i);
           
            // who knows.....
            if (Strings.isNullOrEmpty(line))
                continue;
            // ignore packages and imports
            else if (line.startsWith("package") || line.startsWith("import"))
                continue;
           
            Matcher matcher = classPattern.matcher(line);
           
            // found a class!
            if (matcher.find())
            {
                String newIndent;
                String classPath;
                if (Strings.isNullOrEmpty(qualifiedName))
                {
                    classPath = matcher.group("name");
                    newIndent = indent;
                }
                else
                {
                    classPath = qualifiedName + "." + matcher.group("name");
                    newIndent = indent+ "   ";
                }
               
                // fund an enum class, parse it seperately
                if (matcher.group("type").equals("enum"))
                    processEnum(lines, newIndent, i+1, classPath, matcher.group("name"));
               
                // nested class searching
                i = processClass(lines, newIndent, i+1, classPath, matcher.group("name"));
            }
           
            // class has finished
            if (line.startsWith(indent + "}"))
                return i;
        }
       
        return 0;
    }
   
    private static void processEnum(List<String> lines, String indent, int startIndex, String qualifiedName, String simpleName)
    {
        String newIndent = indent + "   ";
        Pattern enumEntry = Pattern.compile(newIndent + ENUM_ENTRY_REGEX);
        Pattern constructor = Pattern.compile(newIndent + String.format(CONSTRUCTOR_REGEX, simpleName));
        Pattern constructorCall = Pattern.compile(newIndent + "   " + CONSTRUCTOR_CALL_REGEX);
        String formatted = newIndent + String.format(VALUE_FIELD_REGEX, qualifiedName, qualifiedName);
        Pattern valueField = Pattern.compile(formatted);
        String newLine;
        boolean prevSynthetic = false;
       
        for (int i = startIndex; i < lines.size(); i++)
        {
            newLine = null;
            String line = lines.get(i);
           
            // find and replace enum entries
            Matcher matcher = enumEntry.matcher(line);
            if (matcher.find())
            {
                String body = matcher.group("body");
               
                newLine = newIndent + matcher.group("name");
               
                if (!Strings.isNullOrEmpty(body))
                {
                    String[] args = body.split(", ");

                    if (line.endsWith("{"))
                    {
                        if (args[args.length - 1].equals("null"))
                        {
                            args = Arrays.copyOf(args, args.length - 1);
                        }
                    }
                    body = Joiner.on(", ").join(args);
                }
               
                if (Strings.isNullOrEmpty(body))
                    newLine += matcher.group("end");
                else
                    newLine += "(" + body + ")" + matcher.group("end");
            }
           
            // find and replace constructor
            matcher = constructor.matcher(line);
            if (matcher.find())
            {
                StringBuilder tmp = new StringBuilder();
                tmp.append(newIndent).append(matcher.group("modifiers")).append(simpleName).append("(");
               
                String[] args = matcher.group("parameters").split(", ");
                for(int x = 2; x < args.length; x++)
                    tmp.append(args[x]).append(x < args.length - 1 ? ", " : "");
                tmp.append(")");
               
                tmp.append(matcher.group("end"));
                newLine = tmp.toString();
               
                if (args.length <= 2 && newLine.endsWith("}"))
                    newLine = "";
            }
           
            // find constructor calls...
            matcher = constructorCall.matcher(line);
            if (matcher.find())
            {
                String body = matcher.group("body");
               
                if (!Strings.isNullOrEmpty(body))
                {
                    String[] args = body.split(", ");
                    args = Arrays.copyOfRange(args, 2, args.length);
                    body = Joiner.on(", ").join(args);
                }
               
                newLine = newIndent + "   " + matcher.group("name") + "(" + body + ")" + matcher.group("end");
            }
           
            if (prevSynthetic)
            {
                matcher = valueField.matcher(line);
                if (matcher.find())
                    newLine = "";
            }
           
            if (line.contains("// $FF: synthetic field"))
            {
                newLine = "";
                prevSynthetic = true;
            }
            else
                prevSynthetic = false;
           
            if (newLine != null)
                lines.set(i, newLine);
           
            // class has finished.
            if (line.startsWith(indent + "}"))
                break;
        }
    }

    private static String synthetic_replacement(Matcher match)
    {
        //This is designed to remove all the synthetic/bridge methods that the compiler will just generate again
        //First off this only works on methods that bounce to methods that are named exactly alike.
        if (!match.group("method").equals(match.group("method2")))
            return match.group();

        //Next, we normalize the arugment list, if the lists are the same then it's a simple bounce method.
        //MC's code strips generic information so the compiler doesn't know to regen typecast methods
        //Uncomment the two lines below if we ever inject generic info    
        String arg1 = match.group("arguments");
        String arg2 = match.group("arguments2");
        //String arg1 = _REGEXP['typecast'].sub(r'', match.group('arguments'))
        //String arg2 = _REGEXP['typecast'].sub(r'', match.group('arguments2'))

        if (arg1.equals(arg2) && arg1.equals(""))
            return "";
       
        String[] args = match.group("arguments").split(", ");
        for (int x = 0; x < args.length; x++)
            args[x] = args[x].split(" ")[1];
       
        StringBuilder b = new StringBuilder();
        b.append(args[0]);
        for (int x = 1; x < args.length; x++)
            b.append(", ").append(args[x]);
        arg1 = b.toString();
       
        if (arg1.equals(arg2))
            return "";
       
        return match.group();
    }
}
TOP

Related Classes of net.minecraftforge.gradle.extrastuff.FFPatcher

TOP
Copyright © 2015 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.