Search in sources :

Example 6 with ConfigCompileException

use of com.laytonsmith.core.exceptions.ConfigCompileException in project CommandHelper by EngineHub.

the class LexerObject method lex.

public TokenStream lex() throws ConfigCompileException {
    if (token_list != null) {
        return new TokenStream(new ArrayList<Token>(token_list), "");
    } else {
        token_list = new ArrayList<Token>();
    }
    for (int i = 0; i < config.length(); i++) {
        Character c = config.charAt(i);
        Character c2 = null;
        Character c3 = null;
        if (i < config.length() - 1) {
            c2 = config.charAt(i + 1);
        }
        if (i < config.length() - 2) {
            c3 = config.charAt(i + 2);
        }
        column += i - lastColumn;
        lastColumn = i;
        if (c == '\n') {
            line_num++;
            column = 1;
        }
        target = new Target(line_num, file, column);
        // File Options
        if (state_in_fileopts) {
            if (c == '\\' && c2 == '>') {
                // literal >
                fileopts.append('>');
                i++;
                continue;
            } else if (c == '>') {
                state_in_fileopts = false;
                continue;
            } else {
                fileopts.append(c);
                continue;
            }
        }
        // Comments are only applicable if we are not inside a string
        if (!state_in_double_quote && !state_in_single_quote) {
            // If we aren't already in a comment, we might be starting one here
            if (!state_in_block_comment && !state_in_line_comment) {
                if (c == '/' && c2 == '*') {
                    // Start of block comment
                    parseBuffer();
                    state_in_block_comment = true;
                    start_block_comment = line_num;
                    if (c3 == '*') {
                        // It's also a smart block comment
                        state_in_smart_block_comment = true;
                        i++;
                    } else {
                        state_in_smart_block_comment = false;
                    }
                    i++;
                    continue;
                }
                if (c == '#') {
                    parseBuffer();
                    // Start of line comment
                    state_in_line_comment = true;
                    continue;
                }
            } else if (state_in_block_comment) {
                // We might be ending the block comment
                if (c == '*' && c2 == '/') {
                    state_in_block_comment = false;
                    i++;
                    if (state_in_smart_block_comment) {
                    // We need to process the block comment here
                    // TODO:
                    // We need to process the block comment here
                    // TODO:
                    }
                    clearBuffer();
                    continue;
                }
            } else if (state_in_line_comment) {
                if (c == '\n') {
                    state_in_line_comment = false;
                    clearBuffer();
                    continue;
                }
            }
        }
        // Ok, now if we are in a comment, we should just continue
        if (state_in_block_comment || state_in_line_comment) {
            if (state_in_smart_block_comment) {
                buffer(c);
            }
        }
        // Now we need to check for strings
        if (!state_in_double_quote) {
            if (c == '"') {
                parseBuffer();
                // Start of smart string
                state_in_double_quote = true;
                start_double_quote = line_num;
                continue;
            }
        }
        if (!state_in_single_quote) {
            if (c == '\'') {
                // Start of string
                parseBuffer();
                state_in_single_quote = true;
                start_single_quote = line_num;
                continue;
            }
        }
        if (state_in_double_quote || state_in_single_quote) {
            if (c == '\\') {
                // It's an escaped something or another
                switch(c2) {
                    case 'n':
                        buffer("\n");
                        i++;
                        break;
                    case 't':
                        buffer("\t");
                        i++;
                        break;
                    case 'u':
                        StringBuilder unicode = new StringBuilder();
                        for (int m = 0; m < 4; m++) {
                            try {
                                unicode.append(config.charAt(i + 2 + m));
                            } catch (IndexOutOfBoundsException e) {
                                // If this fails, they didn't put enough characters in the stream
                                error("Incomplete unicode escape");
                            }
                        }
                        try {
                            Integer.parseInt(unicode.toString(), 16);
                        } catch (NumberFormatException e) {
                            error("Unrecognized unicode escape sequence");
                        }
                        buffer(Character.toChars(Integer.parseInt(unicode.toString(), 16)));
                        i += 4;
                        break;
                    case '\'':
                        if (state_in_double_quote) {
                            // It's an error if we're in double quotes to escape a single quote
                            error("Invalid escape found. It is an error to escape single quotes inside a double quote.");
                        } else {
                            buffer("'");
                            i++;
                        }
                        break;
                    case '"':
                        if (state_in_single_quote) {
                            // It's an error if we're in single quotes to escape a double quote
                            error("Invalid escape found. It is an error to escape double quotes inside a single quote.");
                        } else {
                            buffer('"');
                            i++;
                        }
                        break;
                    default:
                        // It's invalid, so throw an exception
                        error("The escape sequence \\" + c2 + " is not a recognized escape sequence");
                        break;
                }
                continue;
            }
        }
        // Now deal with ending a quote
        if (state_in_double_quote) {
            if (c == '"') {
                state_in_double_quote = false;
                append(clearBuffer(), Token.TType.SMART_STRING);
                // This is currently an error, but won't be forever
                error("Double quotes are currently unsupported");
                continue;
            } else {
                buffer(c);
                continue;
            }
        }
        if (state_in_single_quote) {
            if (c == '\'') {
                state_in_single_quote = false;
                append(clearBuffer(), Token.TType.STRING);
                continue;
            } else {
                buffer(c);
                continue;
            }
        }
        // Now deal with multiline states
        if (c == '>' && c2 == '>' && c3 == '>') {
            // Multiline start
            if (state_in_multiline) {
                error("Found multiline start symbol while already in multiline!");
            }
            state_in_multiline = true;
            start_multiline = line_num;
            i += 2;
            continue;
        }
        if (c == '<' && c2 == '<' && c3 == '<') {
            if (!state_in_multiline) {
                error("Found multiline end symbol while not in multiline!");
            }
            state_in_multiline = false;
            i += 2;
            continue;
        }
        // Newlines don't count
        if (Character.isWhitespace(c) && c != '\n') {
            // We need to parse the buffer
            parseBuffer();
            continue;
        }
        if (c == '<' && c2 == '!') {
            if (!token_list.isEmpty()) {
                throw new ConfigCompileException("File options must come first in the file.", target);
            }
            state_in_fileopts = true;
            i++;
            continue;
        }
        // get special handling up here, as well as square brackets
        if (!state_in_pure_mscript) {
            if (c == '[') {
                if (state_in_opt_var) {
                    error("Found [ symbol, but a previous optional variable had already been started");
                }
                state_in_opt_var = true;
                parseBuffer();
                append("[", Token.TType.LSQUARE_BRACKET);
                continue;
            }
            if (c == ']') {
                if (!state_in_opt_var) {
                    error("Found ] symbol, but no optional variable had been started");
                }
                state_in_opt_var = false;
                parseBuffer();
                append("]", Token.TType.RSQUARE_BRACKET);
                continue;
            }
            if (state_in_opt_var) {
                if (c == '=') {
                    // This is an optional variable declaration
                    parseBuffer();
                    append("=", Token.TType.OPT_VAR_ASSIGN);
                    continue;
                }
            }
            if (c == '=') {
                state_in_pure_mscript = true;
                parseBuffer();
                append("=", Token.TType.ALIAS_END);
                continue;
            }
            if (c == ':') {
                parseBuffer();
                append(":", Token.TType.LABEL);
                continue;
            }
            if (c == '\n') {
                parseBuffer();
                if (token_list.isEmpty() || token_list.get(token_list.size() - 1).type != TType.NEWLINE) {
                    append("\n", TType.NEWLINE);
                }
                continue;
            }
            // At this point, all other tokens are to be taken literally
            buffer(c);
            continue;
        }
        // kept (except duplicate ones)
        if (c == '\n') {
            if (state_in_multiline) {
                continue;
            } else {
                if (!token_list.isEmpty() && token_list.get(token_list.size() - 1).type != Token.TType.NEWLINE) {
                    parseBuffer();
                    if (usingNonPure) {
                        if (token_list.get(token_list.size() - 1).type != TType.NEWLINE) {
                            // Don't add duplicates
                            append("\n", Token.TType.NEWLINE);
                        }
                        // This also signals the end of pure mscript
                        state_in_pure_mscript = false;
                        continue;
                    } else if (state_in_pure_mscript) {
                        continue;
                    }
                } else {
                    continue;
                }
            }
        }
        // Handle decimal place vs concat
        if (c == '.' && Character.isDigit(c2)) {
            // It'll get identified automatically in a bit
            buffer(c);
            continue;
        }
        // We need to handle /cmd vs division
        if (c == '/' && (c2 == '/' || Character.isLetter(c2))) {
            // It'll be registered as a bare string later
            buffer(c);
            continue;
        }
        // Now we are in pure mscript mode
        // Loop through our token
        int skip;
        if ((skip = identifySymbol(i)) != -1) {
            // Cool, it found one. Jump ahead.
            i += skip;
            continue;
        }
        buffer(c);
    }
    parseBuffer();
    return new TokenStream(new ArrayList<Token>(token_list), fileopts.toString());
}
Also used : Target(com.laytonsmith.core.constructs.Target) Token(com.laytonsmith.core.constructs.Token) ConfigCompileException(com.laytonsmith.core.exceptions.ConfigCompileException)

Example 7 with ConfigCompileException

use of com.laytonsmith.core.exceptions.ConfigCompileException in project CommandHelper by EngineHub.

the class NewMethodScriptCompiler method preprocess.

public static List<NewScript> preprocess(TokenStream tokenStream, Environment compilerEnvironment) throws ConfigCompileException {
    List<NewScript> scripts = new ArrayList<NewScript>();
    // We need to split the command definition and the pure mscript parts. First,
    // we split on newlines, those are each going to be our alias definitions
    List<List<Token>> commands = new ArrayList<List<Token>>();
    List<Token> working = new ArrayList<Token>();
    for (int i = 0; i < tokenStream.size(); i++) {
        Token t = tokenStream.get(i);
        if (t.type == Token.TType.NEWLINE) {
            commands.add(working);
            working = new ArrayList<Token>();
            continue;
        }
        working.add(t);
    }
    // Now they are split into individual aliases
    for (List<Token> stream : commands) {
        // We need to make constructs from the left, and compile the right
        // Compiling the right can be simply passed off to the compile
        // function, but we need to parse the left ourselves
        // We *should* only have (bare) strings, numbers, brackets on the left
        List<Token> left = new ArrayList<Token>();
        TokenStream right = new TokenStream(new ArrayList<Token>(), tokenStream.getFileOptions());
        boolean inLeft = true;
        boolean hasLabel = false;
        for (Token t : stream) {
            if (t.type == Token.TType.ALIAS_END) {
                inLeft = false;
                continue;
            }
            if (t.type == TType.LABEL) {
                hasLabel = true;
            }
            if (inLeft) {
                left.add(t);
            } else {
                right.add(t);
            }
        }
        ParseTree cright = compile(right, compilerEnvironment);
        List<Construct> cleft = new ArrayList<Construct>();
        boolean atFinalVar = false;
        boolean atOptionalVars = false;
        boolean pastLabel = false;
        String label = "";
        try {
            for (int i = 0; i < left.size(); i++) {
                Token t = left.get(i);
                if (hasLabel && !pastLabel) {
                    if (t.type == TType.LABEL) {
                        pastLabel = true;
                        continue;
                    }
                    label += t.val();
                    continue;
                }
                if (atFinalVar) {
                    throw new ConfigCompileException("The final var must be the last declaration in the alias", t.getTarget());
                }
                if (t.type == TType.LSQUARE_BRACKET) {
                    Token tname = left.get(i + 1);
                    atOptionalVars = true;
                    if (tname.val().equals("$")) {
                        atFinalVar = true;
                    }
                    if (tname.type != TType.VARIABLE && tname.type != TType.FINAL_VAR) {
                        throw new ConfigCompileException("Expecting a variable, but found " + tname.val(), tname.getTarget());
                    }
                    i++;
                    Token next = left.get(i + 1);
                    if (next.type != TType.OPT_VAR_ASSIGN && next.type != TType.RSQUARE_BRACKET) {
                        throw new ConfigCompileException("Expecting either a variable assignment or right square bracket, but found " + next.val(), next.getTarget());
                    }
                    i++;
                    String defaultVal = "";
                    if (next.type == TType.OPT_VAR_ASSIGN) {
                        // We have an assignment here
                        Token val = left.get(i + 1);
                        i++;
                        defaultVal = val.val();
                        next = left.get(i + 1);
                    }
                    if (next.type != TType.RSQUARE_BRACKET) {
                        throw new ConfigCompileException("Expecting a right square bracket, but found " + next.val() + " instead. (Did you forget to quote a multi word string?)", next.getTarget());
                    }
                    i++;
                    Variable v = new Variable(tname.val(), defaultVal, true, (tname.val().equals("$")), tname.getTarget());
                    cleft.add(v);
                    continue;
                }
                if (t.type == TType.VARIABLE || t.type == TType.FINAL_VAR) {
                    // Required variable
                    if (atOptionalVars) {
                        throw new ConfigCompileException("Only optional variables may come after the first optional variable", t.getTarget());
                    }
                    if (t.val().equals("$")) {
                        atFinalVar = true;
                    }
                    Variable v = new Variable(t.val(), "", false, t.val().equals("$"), t.getTarget());
                    cleft.add(v);
                    continue;
                }
                cleft.add(tokenToConstruct(t));
            }
        } catch (IndexOutOfBoundsException e) {
            throw new ConfigCompileException("Expecting more tokens, but reached end of alias signature before tokens were resolved.", left.get(0).getTarget());
        }
        if (!cleft.isEmpty()) {
            link(cright, compilerEnvironment);
            scripts.add(new NewScript(cleft, cright, label));
        }
    }
    return scripts;
}
Also used : Variable(com.laytonsmith.core.constructs.Variable) ArrayList(java.util.ArrayList) Token(com.laytonsmith.core.constructs.Token) CBareString(com.laytonsmith.core.constructs.CBareString) CString(com.laytonsmith.core.constructs.CString) ConfigCompileException(com.laytonsmith.core.exceptions.ConfigCompileException) Construct(com.laytonsmith.core.constructs.Construct) ArrayList(java.util.ArrayList) List(java.util.List) ParseTree(com.laytonsmith.core.ParseTree)

Example 8 with ConfigCompileException

use of com.laytonsmith.core.exceptions.ConfigCompileException in project CommandHelper by EngineHub.

the class SimpleBlockKeywordFunction method doProcess.

/**
 * This is the standalone version of the {@link #process(java.util.List, int)} function. All values must be passed
 * in.
 *
 * @param keywordName The keyword name
 * @param functionArgumentCount The function clause argument count
 * @param isStandaloneFunction Whether or not this is a standalone function (that is, it can be used without a block
 * following it)
 * @param list The current list
 * @param keywordPosition The keyword position
 * @return
 * @throws ConfigCompileException
 */
public static int doProcess(String keywordName, Integer[] functionArgumentCount, boolean isStandaloneFunction, List<ParseTree> list, int keywordPosition) throws ConfigCompileException {
    Target t = list.get(keywordPosition).getTarget();
    if (list.size() > keywordPosition + 1) {
        ParseTree code = list.get(keywordPosition + 1);
        if (isCodeBlock(code)) {
            // This is a valid format, but we need to make sure that there is only one argument passed
            // to the while so far.
            Integer[] validArgs = functionArgumentCount;
            // If this is null, we don't care about argument count.
            if (validArgs != null) {
                // If the valid argument count is only 1, we will use that value
                // in the error message to make it more precise. Otherwise, use a more
                // generic error message
                int firstClauseArgumentCount = list.get(keywordPosition).getChildren().size();
                if (validArgs.length == 1) {
                    if (firstClauseArgumentCount != validArgs[0]) {
                        throw new ConfigCompileException("\"" + keywordName + "\" blocks " + (firstClauseArgumentCount > validArgs[0] ? "may only" : "must") + " have " + validArgs[0] + " argument" + (validArgs[0] == 1 ? "" : "s") + " passed to the" + " " + keywordName + " condition, " + firstClauseArgumentCount + " found.", t);
                    }
                } else {
                    boolean error = true;
                    for (int i : validArgs) {
                        if (firstClauseArgumentCount == i) {
                            error = false;
                            break;
                        }
                    }
                    if (error) {
                        throw new ConfigCompileException("\"" + keywordName + "\" blocks may not have " + firstClauseArgumentCount + " argument" + (firstClauseArgumentCount == 1 ? "" : "s") + " passed to the " + keywordName + " condition", t);
                    }
                }
            }
            list.get(keywordPosition).addChild(getArgumentOrNull(code));
            list.remove(keywordPosition + 1);
        }
    } else {
        if (!isStandaloneFunction) {
            throw new ConfigCompileException("Missing code block, following \"" + keywordName + "\"", t);
        }
    }
    return keywordPosition;
}
Also used : Target(com.laytonsmith.core.constructs.Target) ConfigCompileException(com.laytonsmith.core.exceptions.ConfigCompileException) ParseTree(com.laytonsmith.core.ParseTree)

Example 9 with ConfigCompileException

use of com.laytonsmith.core.exceptions.ConfigCompileException in project CommandHelper by EngineHub.

the class TryKeyword method process.

@Override
public int process(List<ParseTree> list, int keywordPosition) throws ConfigCompileException {
    // If it's the old version, and a function
    if (list.get(keywordPosition).getData() instanceof CFunction && list.get(keywordPosition).getData().val().equals("try")) {
        return keywordPosition;
    }
    // Otherwise it's not, and we can continue on, assuming keyword usage.
    this.validateCodeBlock(list.get(keywordPosition + 1), "Expecting braces after try keyword");
    ParseTree complex_try = new ParseTree(new CFunction(COMPLEX_TRY, list.get(keywordPosition).getTarget()), list.get(keywordPosition).getFileOptions());
    complex_try.addChild(getArgumentOrNull(list.get(keywordPosition + 1)));
    // Remove the keyword and the try block
    list.remove(keywordPosition);
    list.remove(keywordPosition);
    // For now, we won't allow try {}, so this must be followed by a catch keyword. This restriction is somewhat artificial, and
    // if we want to remove it in the future, we can do so by removing this code block.
    {
        if (!(list.size() > keywordPosition && (nodeIsCatchKeyword(list.get(keywordPosition)) || nodeIsFinallyKeyword(list.get(keywordPosition))))) {
            throw new ConfigCompileException("Expecting \"catch\" or \"finally\" keyword to follow try, but none found", complex_try.getTarget());
        }
    }
    // We can have any number of catch statements after the try, so we loop through until we run out.
    for (int i = keywordPosition; i < list.size(); i++) {
        if (!nodeIsCatchKeyword(list.get(i)) && !nodeIsFinallyKeyword(list.get(i))) {
            // End of the chain, stop processing.
            break;
        }
        if (list.size() > i + 1) {
            this.validateCodeBlock(list.get(i + 1), "Expecting code block after catch, but none found");
        } else {
            throw new ConfigCompileException("catch must be followed by a code block, but none was found", list.get(i).getTarget());
        }
        if (list.get(i).getData() instanceof CFunction) {
            // We have something like catch(Exception @e) { }
            ParseTree n = list.get(i);
            if (n.getChildren().size() != 1) {
                throw new ConfigCompileException("Unexpected parameters passed to the \"catch\" clause." + " Exactly one argument must be passed.", n.getTarget());
            }
            complex_try.addChild(n.getChildAt(0));
            complex_try.addChild(getArgumentOrNull(list.get(i + 1)));
        } else {
            // clause statement, and we need to verify that there isn't a catch following it.
            if (list.size() > i + 2) {
                if (nodeIsCatchKeyword(list.get(i + 2))) {
                    throw new ConfigCompileException("A finally block must be the final" + " clause in the try/[catch]/finally statement", list.get(i + 2).getTarget());
                }
            }
            // Passed the inspection.
            complex_try.addChild(getArgumentOrNull(list.get(i + 1)));
        }
        // remove the catch keyword and the code block
        list.remove(i);
        list.remove(i);
        --i;
    }
    // Set the new function into place
    list.add(keywordPosition, complex_try);
    return keywordPosition;
}
Also used : CFunction(com.laytonsmith.core.constructs.CFunction) ConfigCompileException(com.laytonsmith.core.exceptions.ConfigCompileException) ParseTree(com.laytonsmith.core.ParseTree)

Example 10 with ConfigCompileException

use of com.laytonsmith.core.exceptions.ConfigCompileException in project CommandHelper by EngineHub.

the class IfKeyword method process.

@Override
public int process(List<ParseTree> list, int keywordPosition) throws ConfigCompileException {
    ParseTree node = list.get(keywordPosition);
    Target t = node.getTarget();
    if (list.size() > keywordPosition + 1) {
        if (this.isValidCodeBlock(list.get(keywordPosition + 1))) {
            // is a compile error.
            if (node.getChildren().size() != 1) {
                throw new ConfigCompileException("Unexpected parameters passed to \"if\" clause, exactly 1 argument" + " must be provided", t);
            }
            // use ifelse from the outset
            try {
                if (nodeIsElseKeyword(list.get(keywordPosition + 2)) && nodeIsIfFunction(list.get(keywordPosition + 3))) {
                    // It is, convert this into an ifelse
                    ParseTree newNode = new ParseTree(new CFunction(IFELSE, t), node.getFileOptions());
                    newNode.setChildren(node.getChildren());
                    list.set(keywordPosition, newNode);
                    node = newNode;
                }
            } catch (IndexOutOfBoundsException ex) {
            // Doesn't matter, we're apparently at the end of the stream
            }
            node.addChild(getArgumentOrNull(list.get(keywordPosition + 1)));
            list.remove(keywordPosition + 1);
        }
        while (list.size() > keywordPosition + 1) {
            // Now check for elses. Since we've removed the cbrace following the if from the tree, we can continue from keywordPostion + 1
            if (nodeIsElseKeyword(list.get(keywordPosition + 1))) {
                try {
                    if (isCodeBlock(list.get(keywordPosition + 2))) {
                        // So ends the chain
                        validateCodeBlock(list.get(keywordPosition + 2), "");
                        node.addChild(getArgumentOrNull(list.get(keywordPosition + 2)));
                        // remove the else keyword + the brace
                        list.remove(keywordPosition + 1);
                        list.remove(keywordPosition + 1);
                        break;
                    } else if (nodeIsIfFunction(list.get(keywordPosition + 2))) {
                        // if(@a){ } else if(@b, @c)
                        if (list.get(keywordPosition + 2).getChildren().size() != 1) {
                            throw new ConfigCompileException("Unexpected parameters passed to \"if\" clause, exactly 1 argument" + " must be provided", list.get(keywordPosition + 2).getTarget());
                        }
                        if (!isCodeBlock(list.get(keywordPosition + 3))) {
                            throw new ConfigCompileException("Expecting braces after \"if\" clause", list.get(keywordPosition + 3).getTarget());
                        }
                        // Ok, checks are complete, so we can actually construct the arguments now
                        node.addChild(list.get(keywordPosition + 2).getChildAt(0));
                        node.addChild(getArgumentOrNull(list.get(keywordPosition + 3)));
                        // Remove the else, if function, and braces
                        list.remove(keywordPosition + 1);
                        list.remove(keywordPosition + 1);
                        list.remove(keywordPosition + 1);
                    } else {
                        // Anything else is unexpected.
                        throw new IndexOutOfBoundsException();
                    }
                } catch (IndexOutOfBoundsException ex) {
                    throw new ConfigCompileException("Expecting either braces, or continuing if statement after \"else\" keyword", list.get(keywordPosition + 1).getTarget());
                }
            } else {
                // Done with the if else chain
                break;
            }
        }
    }
    return keywordPosition;
}
Also used : Target(com.laytonsmith.core.constructs.Target) CFunction(com.laytonsmith.core.constructs.CFunction) ConfigCompileException(com.laytonsmith.core.exceptions.ConfigCompileException) ParseTree(com.laytonsmith.core.ParseTree)

Aggregations

ConfigCompileException (com.laytonsmith.core.exceptions.ConfigCompileException)37 ParseTree (com.laytonsmith.core.ParseTree)16 CFunction (com.laytonsmith.core.constructs.CFunction)14 ArrayList (java.util.ArrayList)13 ConfigCompileGroupException (com.laytonsmith.core.exceptions.ConfigCompileGroupException)12 CString (com.laytonsmith.core.constructs.CString)11 Construct (com.laytonsmith.core.constructs.Construct)8 Token (com.laytonsmith.core.constructs.Token)8 IVariable (com.laytonsmith.core.constructs.IVariable)7 Target (com.laytonsmith.core.constructs.Target)6 GlobalEnv (com.laytonsmith.core.environments.GlobalEnv)6 Function (com.laytonsmith.core.functions.Function)6 Variable (com.laytonsmith.core.constructs.Variable)5 CommandHelperEnvironment (com.laytonsmith.core.environments.CommandHelperEnvironment)5 Environment (com.laytonsmith.core.environments.Environment)5 ConfigRuntimeException (com.laytonsmith.core.exceptions.ConfigRuntimeException)5 FunctionBase (com.laytonsmith.core.functions.FunctionBase)5 File (java.io.File)5 List (java.util.List)5 FunctionList (com.laytonsmith.core.functions.FunctionList)4