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

services.PreprocessFileService Maven / Gradle / Ivy

package services;

import interfaces.IPreprocessFileService;

import java.util.Scanner;

/**
 * A class that can be used before sending data into the abstract syntax tree
 * This will correct some parts of the jass code (like comments and spacing)
 * so that it can be read without error.
 */
public final class PreprocessFileService implements IPreprocessFileService {

    private String text;

    /**
     * Preprocesses the given scanner input
     * Removing comments and normalizing spacing/etc.
     *
     * @param inputScanner  Scanner with data containing the user's input
     * @return New scanner with preprocessed text
     */
    @Override
    public Scanner preprocessFile(Scanner inputScanner) {
        StringBuilder completeText = new StringBuilder();
        // Read the scanner contents into a StringBuilder
        // We will use this StringBuilder to preprocess the code file
        while(inputScanner.hasNextLine()) {
            completeText.append(inputScanner.nextLine()).append("\n");
        }
        // Remove final newline
        if(completeText.length()>0) {
            completeText.setLength(completeText.length()-1);
        }
        this.text = filter(completeText.toString());
        return new Scanner(text);
    }

    /**
     * Removes unnecessary spacing, comments, and newlines from file
     *
     * @param input Input string
     * @return      Input string with unnecessary characters filtered
     */
    private String filter(String input) {
        StringBuilder currentLineOfCode = new StringBuilder();
        StringBuilder assembledCode = new StringBuilder();
        boolean quoted = false; // Set to true if we encounter an unescaped quote
        boolean commented = false; // Set to true if code is commented out
        int numEscapeChars = 0;
        // This logical parsing affects most code text, but does
        // not affect stuff in quotes (text literals that should
        // be left alone)

        for(char c : input.toCharArray()) {
            if(c == '\\') {
                numEscapeChars++;
            }
            if(c == '"') {
                // Handle the quote character
                if(!commented) {
                    // Handle escaped quotes
                    if (numEscapeChars == 0 || numEscapeChars % 2 == 0) {
                        quoted = !quoted;
                    }
                    currentLineOfCode.append(c);
                }
            } else if(c == '\n') {
                // Detect end-of-line if it's not in quotes
                if (!quoted) {
                    // Found the end of our current line of code
                    currentLineOfCode.append(c);
                    commented = false;
                    // Add this line to the assembled lines and clear current
                    String line = currentLineOfCode.toString();
                    currentLineOfCode.setLength(0);
                    assembledCode.append(line.trim()).append("\n");
                } else {
                    // Ignore commented code
                    if(!commented) {
                        currentLineOfCode.append("|n");
                    }
                }
            } else if(currentLineOfCode.length() > 0 && c == 'n' && currentLineOfCode.charAt(currentLineOfCode.length()-1) == '\\') {
                // Handle literal characters "\n" as newline
                // Is this necessary?
                // Try regression testing without it
                if(!commented) {
                    if (!quoted) {
                        currentLineOfCode.append("\n");
                    } else {
                        currentLineOfCode.append(c);
                    }
                }
            } else if (currentLineOfCode.length() > 0 && c == '/' && currentLineOfCode.charAt(currentLineOfCode.length()-1) == '/') {
                // Detect when code gets commented out and ignore that code
                if(!commented) {
                    if (!quoted) {
                        commented = true;
                        // Remove the comment character
                        currentLineOfCode.setLength(currentLineOfCode.length() - 1);
                    } else {
                        currentLineOfCode.append(c);
                    }
                }
            } else {
                // Ignore commented out code
                if(!commented) {
                    currentLineOfCode.append(c);
                }
            }
            if(c != '\\') {
                numEscapeChars = 0;
            }
        }
        // Add the final line of code we found
        String line = currentLineOfCode.toString();
        currentLineOfCode.setLength(0);
        assembledCode.append(line.trim()).append("\n");
        // Final pre-processing before we give back code
        String constructed = assembledCode.toString();
        // Remove empty lines
        while(constructed.contains("\n\n")) {
            constructed = constructed.replace("\n\n","\n");
        }
        // If the code starts with a newline, then remove it
        if(constructed.startsWith("\n")) {
            constructed = constructed.substring(1);
        }
        // If the code ends with a newline, then remove it
        if(constructed.endsWith("\n")) {
            constructed = constructed.substring(0, constructed.length()-1);
        }
        return constructed.trim();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy