Search in sources :

Example 11 with IVariable

use of com.laytonsmith.core.constructs.IVariable in project CommandHelper by EngineHub.

the class Interpreter method execute.

/**
 * This executes an entire script. The cmdline_prompt_event is first triggered (if used) and if the event is
 * cancelled, nothing happens.
 *
 * @param script
 * @param args
 * @param fromFile
 * @throws ConfigCompileException
 * @throws IOException
 */
public void execute(String script, List<String> args, File fromFile) throws ConfigCompileException, IOException, ConfigCompileGroupException {
    CmdlineEvents.cmdline_prompt_input.CmdlinePromptInput input = new CmdlineEvents.cmdline_prompt_input.CmdlinePromptInput(script, inShellMode);
    EventUtils.TriggerListener(Driver.CMDLINE_PROMPT_INPUT, "cmdline_prompt_input", input);
    if (input.isCancelled()) {
        return;
    }
    ctrlCcount = 0;
    if ("exit".equals(script)) {
        if (inShellMode) {
            inShellMode = false;
            return;
        }
        pl(YELLOW + "Use exit() if you wish to exit.");
        return;
    }
    if ("help".equals(script)) {
        pl(getHelpMsg());
        return;
    }
    if (fromFile == null) {
        fromFile = new File("Interpreter");
    }
    boolean localShellMode = false;
    if (!inShellMode && script.startsWith("$$")) {
        localShellMode = true;
        script = script.substring(2);
    }
    if (inShellMode || localShellMode) {
        // Wrap this in shell_adv
        if (doBuiltin(script)) {
            return;
        }
        List<String> shellArgs = StringUtils.ArgParser(script);
        List<String> escapedArgs = new ArrayList<>();
        for (String arg : shellArgs) {
            escapedArgs.add(new CString(arg, Target.UNKNOWN).getQuote());
        }
        script = "shell_adv(" + "array(" + StringUtils.Join(escapedArgs, ",") + ")," + "array(" + "'stdout':closure(@l){sys_out(@l);}," + "'stderr':closure(@l){sys_err(@l);})" + ");";
    }
    isExecuting = true;
    ProfilePoint compile = env.getEnv(GlobalEnv.class).GetProfiler().start("Compilation", LogLevel.VERBOSE);
    final ParseTree tree;
    try {
        TokenStream stream = MethodScriptCompiler.lex(script, fromFile, true);
        tree = MethodScriptCompiler.compile(stream);
    } finally {
        compile.stop();
    }
    // Environment env = Environment.createEnvironment(this.env.getEnv(GlobalEnv.class));
    final List<Variable> vars = new ArrayList<>();
    if (args != null) {
        // Build the @arguments variable, the $ vars, and $ itself. Note that
        // we have special handling for $0, that is the script name, like bash.
        // However, it doesn't get added to either $ or @arguments, due to the
        // uncommon use of it.
        StringBuilder finalArgument = new StringBuilder();
        CArray arguments = new CArray(Target.UNKNOWN);
        {
            // Set the $0 argument
            Variable v = new Variable("$0", "", Target.UNKNOWN);
            v.setVal(fromFile.toString());
            v.setDefault(fromFile.toString());
            vars.add(v);
        }
        for (int i = 0; i < args.size(); i++) {
            String arg = args.get(i);
            if (i > 0) {
                finalArgument.append(" ");
            }
            Variable v = new Variable("$" + Integer.toString(i + 1), "", Target.UNKNOWN);
            v.setVal(new CString(arg, Target.UNKNOWN));
            v.setDefault(arg);
            vars.add(v);
            finalArgument.append(arg);
            arguments.push(new CString(arg, Target.UNKNOWN), Target.UNKNOWN);
        }
        Variable v = new Variable("$", "", false, true, Target.UNKNOWN);
        v.setVal(new CString(finalArgument.toString(), Target.UNKNOWN));
        v.setDefault(finalArgument.toString());
        vars.add(v);
        env.getEnv(GlobalEnv.class).GetVarList().set(new IVariable(CArray.TYPE, "@arguments", arguments, Target.UNKNOWN));
    }
    try {
        ProfilePoint p = this.env.getEnv(GlobalEnv.class).GetProfiler().start("Interpreter Script", LogLevel.ERROR);
        try {
            final MutableObject<Throwable> wasThrown = new MutableObject<>();
            scriptThread = new Thread(new Runnable() {

                @Override
                public void run() {
                    try {
                        MethodScriptCompiler.execute(tree, env, new MethodScriptComplete() {

                            @Override
                            public void done(String output) {
                                if (System.console() != null && !"".equals(output.trim())) {
                                    StreamUtils.GetSystemOut().println(output);
                                }
                            }
                        }, null, vars);
                    } catch (CancelCommandException e) {
                    // Nothing, though we could have been Ctrl+C cancelled, so we need to reset
                    // the interrupt flag. But we do that unconditionally below, in the finally,
                    // in the other thread.
                    } catch (ConfigRuntimeException e) {
                        ConfigRuntimeException.HandleUncaughtException(e, env);
                        // No need for the full stack trace
                        if (System.console() == null) {
                            System.exit(1);
                        }
                    } catch (NoClassDefFoundError e) {
                        StreamUtils.GetSystemErr().println(RED + Main.getNoClassDefFoundErrorMessage(e) + reset());
                        StreamUtils.GetSystemErr().println("Since you're running from standalone interpreter mode, this is not a fatal error, but one of the functions you just used required" + " an actual backing engine that isn't currently loaded. (It still might fail even if you load the engine though.) You simply won't be" + " able to use that function here.");
                        if (System.console() == null) {
                            System.exit(1);
                        }
                    } catch (InvalidEnvironmentException ex) {
                        StreamUtils.GetSystemErr().println(RED + ex.getMessage() + " " + ex.getData() + "() cannot be used in this context.");
                        if (System.console() == null) {
                            System.exit(1);
                        }
                    } catch (RuntimeException e) {
                        pl(RED + e.toString());
                        e.printStackTrace(StreamUtils.GetSystemErr());
                        if (System.console() == null) {
                            System.exit(1);
                        }
                    }
                }
            }, "MethodScript-Main");
            scriptThread.start();
            try {
                scriptThread.join();
            } catch (InterruptedException ex) {
            // 
            }
        } finally {
            p.stop();
        }
    } finally {
        env.getEnv(GlobalEnv.class).SetInterrupt(false);
        isExecuting = false;
    }
}
Also used : TokenStream(com.laytonsmith.core.compiler.TokenStream) InvalidEnvironmentException(com.laytonsmith.core.environments.InvalidEnvironmentException) IVariable(com.laytonsmith.core.constructs.IVariable) Variable(com.laytonsmith.core.constructs.Variable) IVariable(com.laytonsmith.core.constructs.IVariable) ArrayList(java.util.ArrayList) CArray(com.laytonsmith.core.constructs.CArray) CString(com.laytonsmith.core.constructs.CString) ConfigRuntimeException(com.laytonsmith.core.exceptions.ConfigRuntimeException) CString(com.laytonsmith.core.constructs.CString) CmdlineEvents(com.laytonsmith.core.events.drivers.CmdlineEvents) ConfigRuntimeException(com.laytonsmith.core.exceptions.ConfigRuntimeException) CancelCommandException(com.laytonsmith.core.exceptions.CancelCommandException) MutableObject(com.laytonsmith.PureUtilities.Common.MutableObject) ProfilePoint(com.laytonsmith.core.profiler.ProfilePoint) ProfilePoint(com.laytonsmith.core.profiler.ProfilePoint) MethodScriptComplete(com.laytonsmith.core.MethodScriptComplete) GlobalEnv(com.laytonsmith.core.environments.GlobalEnv) File(java.io.File) ParseTree(com.laytonsmith.core.ParseTree)

Example 12 with IVariable

use of com.laytonsmith.core.constructs.IVariable in project CommandHelper by EngineHub.

the class OptimizationUtilities method optimize0.

private static String optimize0(ParseTree node) {
    if (node.getData() instanceof CFunction) {
        StringBuilder b = new StringBuilder();
        boolean first = true;
        b.append(((CFunction) node.getData()).val()).append("(");
        for (ParseTree child : node.getChildren()) {
            if (!first) {
                b.append(",");
            }
            first = false;
            b.append(optimize0(child));
        }
        b.append(")");
        return b.toString();
    } else if (node.getData() instanceof CString) {
        // strings
        return new StringBuilder().append("'").append(node.getData().val().replaceAll("\t", "\\t").replaceAll("\n", "\\n").replace("\\", "\\\\").replace("'", "\\'")).append("'").toString();
    } else if (node.getData() instanceof IVariable) {
        return ((IVariable) node.getData()).getVariableName();
    } else if (node.getData() instanceof Variable) {
        return ((Variable) node.getData()).getVariableName();
    } else if (node.getData() instanceof CSlice) {
        return node.getData().val();
    } else if (node.getData() instanceof CArray) {
        // It's a hardcoded array. This only happens in the course of optimization, if
        // the optimizer adds a new array. We still need to handle it appropriately though.
        // The values in the array will be constant, guaranteed.
        StringBuilder b = new StringBuilder();
        b.append("array(");
        boolean first = true;
        CArray n = (CArray) node.getData();
        for (String key : n.stringKeySet()) {
            if (!first) {
                b.append(",");
            }
            first = false;
            b.append(optimize0(new ParseTree(n.get(key, Target.UNKNOWN), node.getFileOptions())));
        }
        b.append(")");
        return b.toString();
    } else {
        // static
        return node.getData().toString();
    }
}
Also used : Variable(com.laytonsmith.core.constructs.Variable) IVariable(com.laytonsmith.core.constructs.IVariable) IVariable(com.laytonsmith.core.constructs.IVariable) CSlice(com.laytonsmith.core.constructs.CSlice) CArray(com.laytonsmith.core.constructs.CArray) CFunction(com.laytonsmith.core.constructs.CFunction) CString(com.laytonsmith.core.constructs.CString) ParseTree(com.laytonsmith.core.ParseTree) CString(com.laytonsmith.core.constructs.CString)

Example 13 with IVariable

use of com.laytonsmith.core.constructs.IVariable in project CommandHelper by EngineHub.

the class CompositeFunction method exec.

@Override
public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException {
    ParseTree tree;
    if (!cachedScripts.containsKey(this.getClass())) {
        try {
            String script = script();
            tree = MethodScriptCompiler.compile(MethodScriptCompiler.lex(script, null, true)).getChildAt(0);
        } catch (ConfigCompileException | ConfigCompileGroupException ex) {
            // This is really bad.
            throw new Error(ex);
        }
        if (cacheCompile()) {
            cachedScripts.put(this.getClass(), tree);
        }
    } else {
        tree = cachedScripts.get(this.getClass());
    }
    GlobalEnv env = environment.getEnv(GlobalEnv.class);
    IVariableList oldVariables = env.GetVarList();
    IVariableList newVariables = new IVariableList();
    newVariables.set(new IVariable(CClassType.get("array"), "@arguments", new CArray(t, args.length, args), t));
    env.SetVarList(newVariables);
    Construct ret = CVoid.VOID;
    try {
        env.GetScript().eval(tree, environment);
    } catch (FunctionReturnException ex) {
        ret = ex.getReturn();
    }
    env.SetVarList(oldVariables);
    return ret;
}
Also used : IVariable(com.laytonsmith.core.constructs.IVariable) IVariableList(com.laytonsmith.core.constructs.IVariableList) CArray(com.laytonsmith.core.constructs.CArray) Construct(com.laytonsmith.core.constructs.Construct) GlobalEnv(com.laytonsmith.core.environments.GlobalEnv) FunctionReturnException(com.laytonsmith.core.exceptions.FunctionReturnException) ConfigCompileGroupException(com.laytonsmith.core.exceptions.ConfigCompileGroupException) ConfigCompileException(com.laytonsmith.core.exceptions.ConfigCompileException) ParseTree(com.laytonsmith.core.ParseTree)

Example 14 with IVariable

use of com.laytonsmith.core.constructs.IVariable in project CommandHelper by EngineHub.

the class MethodScriptCompiler method optimize.

/**
 * Recurses down into the tree, attempting to optimize where possible. A few things have strong coupling, for
 * information on these items, see the documentation included in the source.
 *
 * @param tree
 * @return
 */
private static void optimize(ParseTree tree, Stack<List<Procedure>> procs, Set<ConfigCompileException> compilerErrors) {
    if (tree.isOptimized()) {
        // Don't need to re-run this
        return;
    }
    // }
    if (!(tree.getData() instanceof CFunction)) {
        // There's no way to optimize something that's not a function
        return;
    }
    // If it is a proc definition, we need to go ahead and see if we can add it to the const proc stack
    if (tree.getData().val().equals("proc")) {
        procs.push(new ArrayList<Procedure>());
    }
    CFunction cFunction = (CFunction) tree.getData();
    Function func;
    try {
        func = (Function) FunctionList.getFunction(cFunction);
    } catch (ConfigCompileException e) {
        func = null;
    }
    if (func != null) {
        if (func.getClass().getAnnotation(nolinking.class) != null) {
            // It's an unlinking function, so we need to stop at this point
            return;
        }
    }
    if (cFunction instanceof CIdentifier) {
        // Add the child to the identifier
        ParseTree c = ((CIdentifier) cFunction).contained();
        tree.addChild(c);
        c.getData().setWasIdentifier(true);
    }
    List<ParseTree> children = tree.getChildren();
    if (func instanceof Optimizable && ((Optimizable) func).optimizationOptions().contains(OptimizationOption.PRIORITY_OPTIMIZATION)) {
        // would cause an error, even though the user did in fact provide code in that section.
        try {
            ((Optimizable) func).optimizeDynamic(tree.getTarget(), children, tree.getFileOptions());
        } catch (ConfigCompileException ex) {
            // If an error occurs, we will skip the rest of this element
            compilerErrors.add(ex);
            return;
        } catch (ConfigRuntimeException ex) {
            compilerErrors.add(new ConfigCompileException(ex));
            return;
        }
    }
    for (int i = 0; i < children.size(); i++) {
        ParseTree t = children.get(i);
        if (t.getData() instanceof CFunction) {
            if (t.getData().val().startsWith("_") || (func != null && func.useSpecialExec())) {
                continue;
            }
            Function f;
            try {
                f = (Function) FunctionList.getFunction(t.getData());
            } catch (ConfigCompileException ex) {
                compilerErrors.add(ex);
                return;
            }
            Set<OptimizationOption> options = NO_OPTIMIZATIONS;
            if (f instanceof Optimizable) {
                options = ((Optimizable) f).optimizationOptions();
            }
            if (options.contains(OptimizationOption.TERMINAL)) {
                if (children.size() > i + 1) {
                    // First, a compiler warning
                    CHLog.GetLogger().Log(CHLog.Tags.COMPILER, LogLevel.WARNING, "Unreachable code. Consider removing this code.", children.get(i + 1).getTarget());
                    // Now, truncate the children
                    for (int j = children.size() - 1; j > i; j--) {
                        children.remove(j);
                    }
                    break;
                }
            }
        }
    }
    boolean fullyStatic = true;
    boolean hasIVars = false;
    for (ParseTree node : children) {
        if (node.getData() instanceof CFunction) {
            optimize(node, procs, compilerErrors);
        }
        if (node.getData().isDynamic() && !(node.getData() instanceof IVariable)) {
            fullyStatic = false;
        }
        if (node.getData() instanceof IVariable) {
            hasIVars = true;
        }
    }
    // In all cases, at this point, we are either unable to optimize, or we will
    // optimize, so set our optimized variable at this point.
    tree.setOptimized(true);
    if (func == null) {
        // It's a proc call. Let's see if we can optimize it
        Procedure p = null;
        loop: for (List<Procedure> proc : procs) {
            for (Procedure pp : proc) {
                if (pp.getName().equals(cFunction.val())) {
                    p = pp;
                    break loop;
                }
            }
        }
        if (p != null) {
            try {
                Construct c = DataHandling.proc.optimizeProcedure(p.getTarget(), p, children);
                if (c != null) {
                    tree.setData(c);
                    tree.removeChildren();
                    return;
                }
            // else Nope, couldn't optimize.
            } catch (ConfigRuntimeException ex) {
                // Cool. Caught a runtime error at compile time :D
                compilerErrors.add(new ConfigCompileException(ex));
            }
        }
        // so we can't for sure say, but we do know we can't optimize this
        return;
    }
    if (tree.getData().val().equals("proc")) {
        // Check for too few arguments
        if (children.size() < 2) {
            compilerErrors.add(new ConfigCompileException("Incorrect number of arguments passed to proc", tree.getData().getTarget()));
            return;
        }
        // We just went out of scope, so we need to pop the layer of Procedures that
        // are internal to us
        procs.pop();
        // Let's see.
        try {
            ParseTree root = new ParseTree(new CFunction(__autoconcat__, Target.UNKNOWN), tree.getFileOptions());
            Script fakeScript = Script.GenerateScript(root, "*");
            Environment env = null;
            try {
                if (Implementation.GetServerType().equals(Implementation.Type.BUKKIT)) {
                    CommandHelperPlugin plugin = CommandHelperPlugin.self;
                    GlobalEnv gEnv = new GlobalEnv(plugin.executionQueue, plugin.profiler, plugin.persistenceNetwork, MethodScriptFileLocations.getDefault().getConfigDirectory(), plugin.profiles, new TaskManager());
                    env = Environment.createEnvironment(gEnv, new CommandHelperEnvironment());
                } else {
                    env = Static.GenerateStandaloneEnvironment(false);
                }
            } catch (IOException | DataSourceException | URISyntaxException | Profiles.InvalidProfileException e) {
            // 
            }
            Procedure myProc = DataHandling.proc.getProcedure(tree.getTarget(), env, fakeScript, children.toArray(new ParseTree[children.size()]));
            // Yep. So, we can move on with our lives now, and if it's used later, it could possibly be static.
            procs.peek().add(myProc);
        } catch (ConfigRuntimeException e) {
            // Well, they have an error in there somewhere
            compilerErrors.add(new ConfigCompileException(e));
        } catch (NullPointerException e) {
            // Nope, can't optimize.
            return;
        }
    }
    // the compiler trick functions know how to deal with it specially, even if everything isn't
    // static, so do this first.
    String oldFunctionName = func.getName();
    Set<OptimizationOption> options = NO_OPTIMIZATIONS;
    if (func instanceof Optimizable) {
        options = ((Optimizable) func).optimizationOptions();
    }
    if (options.contains(OptimizationOption.OPTIMIZE_DYNAMIC)) {
        try {
            ParseTree tempNode;
            try {
                tempNode = ((Optimizable) func).optimizeDynamic(tree.getData().getTarget(), tree.getChildren(), tree.getFileOptions());
            } catch (ConfigRuntimeException e) {
                // Turn it into a compile exception, then rethrow
                throw new ConfigCompileException(e);
            }
            if (tempNode == Optimizable.PULL_ME_UP) {
                if (tree.hasChildren()) {
                    tempNode = tree.getChildAt(0);
                } else {
                    tempNode = null;
                }
            }
            if (tempNode == Optimizable.REMOVE_ME) {
                tree.setData(new CFunction("p", Target.UNKNOWN));
                tree.removeChildren();
            } else if (tempNode != null) {
                tree.setData(tempNode.getData());
                tree.setOptimized(tempNode.isOptimized());
                tree.setChildren(tempNode.getChildren());
                tree.getData().setWasIdentifier(tempNode.getData().wasIdentifier());
                optimize(tree, procs, compilerErrors);
                tree.setOptimized(true);
                // array, so if they have reversed this, make note of that now
                if (tempNode.hasBeenMadeStatic()) {
                    fullyStatic = true;
                }
            }
        // else it wasn't an optimization, but a compile check
        } catch (ConfigCompileException ex) {
            compilerErrors.add(ex);
        }
    }
    if (!fullyStatic) {
        return;
    }
    // specially from here forward
    if (func.preResolveVariables() && hasIVars) {
        // Well, this function isn't equipped to deal with IVariables.
        return;
    }
    // don't want to run this now
    if (tree.getData().getValue().equals(oldFunctionName) && (options.contains(OptimizationOption.OPTIMIZE_CONSTANT) || options.contains(OptimizationOption.CONSTANT_OFFLINE))) {
        Construct[] constructs = new Construct[tree.getChildren().size()];
        for (int i = 0; i < tree.getChildren().size(); i++) {
            constructs[i] = tree.getChildAt(i).getData();
        }
        try {
            try {
                Construct result;
                if (options.contains(OptimizationOption.CONSTANT_OFFLINE)) {
                    List<Integer> numArgsList = Arrays.asList(func.numArgs());
                    if (!numArgsList.contains(Integer.MAX_VALUE) && !numArgsList.contains(tree.getChildren().size())) {
                        compilerErrors.add(new ConfigCompileException("Incorrect number of arguments passed to " + tree.getData().val(), tree.getData().getTarget()));
                        result = null;
                    } else {
                        result = func.exec(tree.getData().getTarget(), null, constructs);
                    }
                } else {
                    result = ((Optimizable) func).optimize(tree.getData().getTarget(), constructs);
                }
                // If the result is null, it was just a check, it can't optimize further.
                if (result != null) {
                    result.setWasIdentifier(tree.getData().wasIdentifier());
                    tree.setData(result);
                    tree.removeChildren();
                }
            } catch (ConfigRuntimeException e) {
                // Turn this into a ConfigCompileException, then rethrow
                throw new ConfigCompileException(e);
            }
        } catch (ConfigCompileException ex) {
            compilerErrors.add(ex);
        }
    }
// It doesn't know how to optimize. Oh well.
}
Also used : CommandHelperPlugin(com.laytonsmith.commandhelper.CommandHelperPlugin) IVariable(com.laytonsmith.core.constructs.IVariable) ConfigRuntimeException(com.laytonsmith.core.exceptions.ConfigRuntimeException) URISyntaxException(java.net.URISyntaxException) CString(com.laytonsmith.core.constructs.CString) ConfigCompileException(com.laytonsmith.core.exceptions.ConfigCompileException) Function(com.laytonsmith.core.functions.Function) CFunction(com.laytonsmith.core.constructs.CFunction) CommandHelperEnvironment(com.laytonsmith.core.environments.CommandHelperEnvironment) KeywordList(com.laytonsmith.core.compiler.KeywordList) FunctionList(com.laytonsmith.core.functions.FunctionList) List(java.util.List) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) com.laytonsmith.annotations.nolinking(com.laytonsmith.annotations.nolinking) OptimizationOption(com.laytonsmith.core.Optimizable.OptimizationOption) CFunction(com.laytonsmith.core.constructs.CFunction) IOException(java.io.IOException) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) TaskManager(com.laytonsmith.core.taskmanager.TaskManager) DataSourceException(com.laytonsmith.persistence.DataSourceException) CIdentifier(com.laytonsmith.core.constructs.CIdentifier) Construct(com.laytonsmith.core.constructs.Construct) CommandHelperEnvironment(com.laytonsmith.core.environments.CommandHelperEnvironment) Environment(com.laytonsmith.core.environments.Environment) GlobalEnv(com.laytonsmith.core.environments.GlobalEnv)

Example 15 with IVariable

use of com.laytonsmith.core.constructs.IVariable in project CommandHelper by EngineHub.

the class Procedure method checkPossiblyConstant.

private boolean checkPossiblyConstant(ParseTree tree) {
    // individual procs need to be inlined as deemed appropriate.
    if (true) {
        return false;
    }
    if (!tree.getData().isDynamic()) {
        // If it isn't dynamic, it certainly could be constant
        return true;
    } else if (tree.getData() instanceof IVariable) {
        // contract, but import() itself is dynamic, so this is not an issue.
        return true;
    } else if (tree.getData() instanceof CFunction) {
        // If the function itself is not optimizable, we needn't recurse.
        try {
            FunctionBase fb = FunctionList.getFunction(tree.getData());
            if (fb instanceof Function) {
                Function f = (Function) fb;
                if (f instanceof DataHandling._return) {
                    // but if the contents are optimizable, it is still considered constant.
                    if (!tree.hasChildren()) {
                        return true;
                    } else {
                        return checkPossiblyConstant(tree.getChildAt(0));
                    }
                }
                // If it's optimizable, it's possible. If it's restricted, it doesn't matter, because
                // we can't optimize it out anyways, because we need to do the permission check
                Set<Optimizable.OptimizationOption> o = EnumSet.noneOf(Optimizable.OptimizationOption.class);
                if (f instanceof Optimizable) {
                    o = ((Optimizable) f).optimizationOptions();
                }
                if (!((o != null && (o.contains(Optimizable.OptimizationOption.OPTIMIZE_DYNAMIC) || o.contains(Optimizable.OptimizationOption.OPTIMIZE_CONSTANT))) && !f.isRestricted())) {
                    // Nope. Doesn't matter if the children are or not
                    return false;
                }
            } else {
                return false;
            }
        } catch (ConfigCompileException e) {
        // It's a proc. We will treat this just like any other function call,
        }
        // Ok, well, we have to check the children first.
        for (ParseTree child : tree.getChildren()) {
            if (!checkPossiblyConstant(child)) {
                // Nope, since our child can't be constant, neither can we
                return false;
            }
        }
        // They all check out, so, yep, we could possibly be constant
        return true;
    } else {
        // Uh. Ok, well, nope.
        return false;
    }
}
Also used : CFunction(com.laytonsmith.core.constructs.CFunction) Function(com.laytonsmith.core.functions.Function) FunctionBase(com.laytonsmith.core.functions.FunctionBase) IVariable(com.laytonsmith.core.constructs.IVariable) CFunction(com.laytonsmith.core.constructs.CFunction) ConfigCompileException(com.laytonsmith.core.exceptions.ConfigCompileException)

Aggregations

IVariable (com.laytonsmith.core.constructs.IVariable)16 Construct (com.laytonsmith.core.constructs.Construct)10 CString (com.laytonsmith.core.constructs.CString)9 CArray (com.laytonsmith.core.constructs.CArray)8 GlobalEnv (com.laytonsmith.core.environments.GlobalEnv)8 CFunction (com.laytonsmith.core.constructs.CFunction)6 ConfigRuntimeException (com.laytonsmith.core.exceptions.ConfigRuntimeException)6 ConfigCompileException (com.laytonsmith.core.exceptions.ConfigCompileException)5 Variable (com.laytonsmith.core.constructs.Variable)4 Environment (com.laytonsmith.core.environments.Environment)4 ArrayList (java.util.ArrayList)4 ParseTree (com.laytonsmith.core.ParseTree)3 CDouble (com.laytonsmith.core.constructs.CDouble)3 CInt (com.laytonsmith.core.constructs.CInt)3 CNull (com.laytonsmith.core.constructs.CNull)3 IVariableList (com.laytonsmith.core.constructs.IVariableList)3 CommandHelperEnvironment (com.laytonsmith.core.environments.CommandHelperEnvironment)3 ConfigCompileGroupException (com.laytonsmith.core.exceptions.ConfigCompileGroupException)3 FunctionReturnException (com.laytonsmith.core.exceptions.FunctionReturnException)3 FunctionList (com.laytonsmith.core.functions.FunctionList)3