All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.minecraftforge.gradle.util.mcp.McpCleanup Maven / Gradle / Ivy

/*
 * A Gradle plugin for the creation of Minecraft mods and MinecraftForge plugins.
 * Copyright (C) 2013-2019 Minecraft Forge
 * Copyright (C) 2020-2021 anatawa12 and other contributors
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
 * USA
 */
package net.minecraftforge.gradle.util.mcp;

import java.io.StringWriter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import net.minecraftforge.gradle.common.Constants;

public class McpCleanup
{
    public static final Pattern COMMENTS_TRAILING = Pattern.compile("(?m)[ \\t]+$");
    public static final Pattern COMMENTS_NEWLINES = Pattern.compile("(?m)^(?:\\r\\n|\\r|\\n){2,}");

    enum CommentState
    {
        CODE,
        STRING,
        CHARACTER,
        SINGLE_LINE_COMMENT,
        MULTI_LINE_COMMENT,
    }

    public static String stripComments(String text)
    {
        CommentState state = CommentState.CODE;
        int i = 0;
        try (StringWriter out = new StringWriter(text.length()))
        {
            while (i < text.length())
            {
                if (state == CommentState.CODE)
                {
                    out.write(text.charAt(i++));
                }
                else if (state == CommentState.STRING || state == CommentState.CHARACTER)
                {
                    // write the first quote
                    out.write(text.charAt(i++));
                    char end = state == CommentState.STRING ? '"' : '\'';
                    while (i < text.length() && text.charAt(i) != end)
                    {
                        // escape characters
                        if (text.charAt(i) == '\\')
                        {
                            out.write(text.charAt(i++));
                        }
                        // the slash might have been the last character
                        if (i >= text.length())
                        {
                            break;
                        }
                        out.write(text.charAt(i++));
                    }
                    // write the second quote
                    // check because the text might not have ended
                    if (i < text.length())
                    {
                        out.write(text.charAt(i++));
                    }
                }
                else if (state == CommentState.SINGLE_LINE_COMMENT)
                {
                    i += 2; // skip "//"
                    while (i < text.length() && text.charAt(i) != '\n' && text.charAt(i) != '\r')
                    {
                        i++;
                    }
                    //i += 1; // skip the ending newline
                    // Successive new lines will be fixed by our regex below.
                }
                else // state == CommentState.MULTI_LINE_COMMENT
                {
                    i += 2; // skip "/*"
                    while (i < text.length() && (text.charAt(i) != '*' || text.charAt(i + 1) != '/'))
                    {
                        i++;
                    }
                    i += 2; //skip "*/"
                }
                state = null;
                if (i < text.length())
                {
                    if (text.charAt(i) == '"')
                    {
                        state = CommentState.STRING;
                    }
                    else if (text.charAt(i) == '\'')
                    {
                        state = CommentState.CHARACTER;
                    }
                }
                if (i + 1 < text.length() && state == null)
                {
                    if (text.charAt(i) == '/' && text.charAt(i + 1) == '/')
                    {
                        state = CommentState.SINGLE_LINE_COMMENT;
                    }
                    else if (text.charAt(i) == '/' && text.charAt(i + 1) == '*')
                    {
                        state = CommentState.MULTI_LINE_COMMENT;
                    }
                }
                if (state == null)
                {
                    state = CommentState.CODE;
                }
            }
            text = out.toString();
        }
        catch (Exception e)
        {
            throw new RuntimeException(e);
        }

        text = COMMENTS_TRAILING.matcher(text).replaceAll("");
        text = COMMENTS_NEWLINES.matcher(text).replaceAll(Constants.NEWLINE);

        return text;
    }

    //---------------------------------------------
    //  CLEANUP REGEXES.
    //----------------------------------------------

    public static final Pattern CLEANUP_header = Pattern.compile("^\\s+"); // Remove extra whitespace at start of file

    public static final Pattern CLEANUP_footer = Pattern.compile("\\s+$"); // Remove extra whitespace at end of file

    public static final Pattern CLEANUP_trailing = Pattern.compile("(?m)[ \\t]+$"); // Remove TRAILING whitespace

    public static final Pattern CLEANUP_package = Pattern.compile("(?m)^package ([\\w.]+);$"); // find package --- in quots since its a special word

    public static final Pattern CLEANUP_import = Pattern.compile("(?m)^import (?:([\\w.]*?)\\.)?(?:[\\w]+);(?:\\r\\n|\\r|\\n)"); // package and class.

    public static final Pattern CLEANUP_newlines = Pattern.compile("(?m)^\\s*(?:\\r\\n|\\r|\\n){2,}"); // remove repeated blank lines   ?? JDT?

    public static final Pattern CLEANUP_ifstarts = Pattern.compile("(?m)(^(?![\\s{}]*$).+(?:\\r\\n|\\r|\\n))((?:[ \\t]+)if.*)"); // add new line before IF statements

    // close up blanks in code like:
    // {
    //
    //     private
    public static final Pattern CLEANUP_blockstarts = Pattern.compile("(?m)(?<=\\{)\\s+(?=(?:\\r\\n|\\r|\\n)[ \\t]*\\S)");

    // close up blanks in code like:
    //     }
    //
    // }
    public static final Pattern CLEANUP_blockends = Pattern.compile("(?m)(?<=[;}])\\s+(?=(?:\\r\\n|\\r|\\n)\\s*})");

    // Remove GL comments and surrounding whitespace
    public static final Pattern CLEANUP_gl = Pattern.compile("\\s*\\/\\*\\s*GL_[^*]+\\*\\/\\s*");

    // convert unicode character constants back to integers
    public static final Pattern CLEANUP_unicode = Pattern.compile("'\\\\u([0-9a-fA-F]{4})'");

    // strip out Character.valueof
    public static final Pattern CLEANUP_charval = Pattern.compile("Character\\.valueOf\\(('.')\\)");

    // 1.7976...E+308D to Double.MAX_VALUE
    public static final Pattern CLEANUP_maxD = Pattern.compile("1\\.7976[0-9]*[Ee]\\+308[Dd]");

    // 3.1415...D to Math.PI
    public static final Pattern CLEANUP_piD = Pattern.compile("3\\.1415[0-9]*[Dd]");

    // 3.1415...F to (float)Math.PI
    public static final Pattern CLEANUP_piF = Pattern.compile("3\\.1415[0-9]*[Ff]");

    // 6.2831...D to (Math.PI * 2D)
    public static final Pattern CLEANUP_2piD = Pattern.compile("6\\.2831[0-9]*[Dd]");

    // 6.2831...F to ((float)Math.PI * 2F)
    public static final Pattern CLEANUP_2piF = Pattern.compile("6\\.2831[0-9]*[Ff]");

    // 1.5707...D to (Math.PI / 2D)
    public static final Pattern CLEANUP_pi2D = Pattern.compile("1\\.5707[0-9]*[Dd]");

    // 1.5707...F to ((float)Math.PI / 2F)
    public static final Pattern CLEANUP_pi2F = Pattern.compile("1\\.5707[0-9]*[Ff]");

    // 4.7123...D to (Math.PI * 3D / 2D)
    public static final Pattern CLEANUP_3pi2D = Pattern.compile("4\\.7123[0-9]*[Dd]");

    // 4.7123...F to ((float)Math.PI * 3F / 2F)
    public static final Pattern CLEANUP_3pi2F = Pattern.compile("4\\.7123[0-9]*[Ff]");

    // 0.7853...D to (Math.PI / 4D)
    public static final Pattern CLEANUP_pi4D = Pattern.compile("0\\.7853[0-9]*[Dd]");

    // 0.7853...F to ((float)Math.PI / 4F)
    public static final Pattern CLEANUP_pi4F = Pattern.compile("0\\.7853[0-9]*[Ff]");

    // 0.6283...D to (Math.PI / 5D)
    public static final Pattern CLEANUP_pi5D = Pattern.compile("0\\.6283[0-9]*[Dd]");

    // 0.6283...F to ((float)Math.PI / 5F)
    public static final Pattern CLEANUP_pi5F = Pattern.compile("0\\.6283[0-9]*[Ff]");

    // 57.295...D to (180D / Math.PI)
    public static final Pattern CLEANUP_180piD = Pattern.compile("57\\.295[0-9]*[Dd]");

    // 57.295...F to (180F / (float)Math.PI)
    public static final Pattern CLEANUP_180piF = Pattern.compile("57\\.295[0-9]*[Ff]");

    // 0.6981...D to (Math.PI * 2D / 9D)
    public static final Pattern CLEANUP_2pi9D = Pattern.compile("0\\.6981[0-9]*[Dd]");

    // 0.6981...F to ((float)Math.PI * 2F / 9F)
    public static final Pattern CLEANUP_2pi9F = Pattern.compile("0\\.6981[0-9]*[Ff]");

    // 0.3141...D to (Math.PI / 10D)
    public static final Pattern CLEANUP_pi10D = Pattern.compile("0\\.3141[0-9]*[Dd]");

    // 0.3141...F to ((float)Math.PI / 10F)
    public static final Pattern CLEANUP_pi10F = Pattern.compile("0\\.3141[0-9]*[Ff]");

    // 1.2566...D to (Math.PI * 2D / 5D)
    public static final Pattern CLEANUP_2pi5D = Pattern.compile("1\\.2566[0-9]*[Dd]");

    // 1.2566...F to ((float)Math.PI 2F / 5F)
    public static final Pattern CLEANUP_2pi5F = Pattern.compile("1\\.2566[0-9]*[Ff]");

    // 0.21991...D to (Math.PI * 7D / 100D)
    public static final Pattern CLEANUP_7pi100D = Pattern.compile("0\\.21991[0-9]*[Dd]");

    // 0.21991...F to ((float)Math.PI * 7F / 100F)
    public static final Pattern CLEANUP_7pi100F = Pattern.compile("0\\.21991[0-9]*[Ff]");

    // 5.8119...D to (Math.PI * 185D / 100D)
    public static final Pattern CLEANUP_185pi100D = Pattern.compile("5\\.8119[0-9]*[Dd]");

    // 5.8119...F to ((float)Math.PI * 185F / 100F)
    public static final Pattern CLEANUP_185pi100F = Pattern.compile("0\\.8119[0-9]*[Ff]");

    public static String cleanup(String text)
    {
        // simple replacements
        text = CLEANUP_header.matcher(text).replaceAll("");
        text = CLEANUP_footer.matcher(text).replaceAll("");
        text = CLEANUP_trailing.matcher(text).replaceAll("");
        text = CLEANUP_newlines.matcher(text).replaceAll(Constants.NEWLINE);
        text = CLEANUP_ifstarts.matcher(text).replaceAll("$1" + Constants.NEWLINE + "$2");
        text = CLEANUP_blockstarts.matcher(text).replaceAll("");
        text = CLEANUP_blockends.matcher(text).replaceAll("");
        text = CLEANUP_gl.matcher(text).replaceAll("");
        text = CLEANUP_maxD.matcher(text).replaceAll("Double.MAX_VALUE");

        // unicode chars
        {
            Matcher matcher = CLEANUP_unicode.matcher(text);
            int val;
            StringBuffer buffer = new StringBuffer(text.length());

            while (matcher.find())
            {
                val = Integer.parseInt(matcher.group(1), 16);
                // work around the replace('\u00a7', '$') call in MinecraftServer and a couple of '\u0000'
                if (val > 255)
                {
                    matcher.appendReplacement(buffer, Matcher.quoteReplacement("" + val));
                }
            }
            matcher.appendTail(buffer);
            text = buffer.toString();
        }

        // charval.. its stupid.
        text = CLEANUP_charval.matcher(text).replaceAll("$1"); // TESTING NEEDED

        //         pi?   true
        text = CLEANUP_piD.matcher(text).replaceAll("Math.PI");
        text = CLEANUP_piF.matcher(text).replaceAll("(float)Math.PI");
        text = CLEANUP_2piD.matcher(text).replaceAll("(Math.PI * 2D)");
        text = CLEANUP_2piF.matcher(text).replaceAll("((float)Math.PI * 2F)");
        text = CLEANUP_pi2D.matcher(text).replaceAll("(Math.PI / 2D)");
        text = CLEANUP_pi2F.matcher(text).replaceAll("((float)Math.PI / 2F)");
        text = CLEANUP_3pi2D.matcher(text).replaceAll("(Math.PI * 3D / 2D)");
        text = CLEANUP_3pi2F.matcher(text).replaceAll("((float)Math.PI * 3F / 2F)");
        text = CLEANUP_pi4D.matcher(text).replaceAll("(Math.PI / 4D)");
        text = CLEANUP_pi4F.matcher(text).replaceAll("((float)Math.PI / 4F)");
        text = CLEANUP_pi5D.matcher(text).replaceAll("(Math.PI / 5D)");
        text = CLEANUP_pi5F.matcher(text).replaceAll("((float)Math.PI / 5F)");
        text = CLEANUP_180piD.matcher(text).replaceAll("(180D / Math.PI)");
        text = CLEANUP_180piF.matcher(text).replaceAll("(180F / (float)Math.PI)");
        text = CLEANUP_2pi9D.matcher(text).replaceAll("(Math.PI * 2D / 9D)");
        text = CLEANUP_2pi9F.matcher(text).replaceAll("((float)Math.PI * 2F / 9F)");
        text = CLEANUP_pi10D.matcher(text).replaceAll("(Math.PI / 10D)");
        text = CLEANUP_pi10F.matcher(text).replaceAll("((float)Math.PI / 10F)");
        text = CLEANUP_2pi5D.matcher(text).replaceAll("(Math.PI * 2D / 5D)");
        text = CLEANUP_2pi5F.matcher(text).replaceAll("((float)Math.PI * 2F / 5F)");
        text = CLEANUP_7pi100D.matcher(text).replaceAll("(Math.PI * 7D / 100D)");
        text = CLEANUP_7pi100F.matcher(text).replaceAll("((float)Math.PI * 7F / 100F)");
        text = CLEANUP_185pi100D.matcher(text).replaceAll("(Math.PI * 185D / 100D)");
        text = CLEANUP_185pi100F.matcher(text).replaceAll("((float)Math.PI * 185F / 100F)");

        return text;
    }

    /**
     * Ensures that no class imports stuff from the package its in.
     *
     * @param text Full file as a string
     * @return Full file as a string with imports fixed.
     */
    public static String fixImports(String text)
    {
        Matcher match = CLEANUP_package.matcher(text);
        if (match.find())
        {
            String pack = match.group(1);

            Matcher match2 = CLEANUP_import.matcher(text);
            while (match2.find())
            {
                if (match2.group(1).equals(pack))
                {
                    text = text.replace(match2.group(), "");
                }
            }
        }

        return text;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy