]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/commands/CommandSession.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / commands / CommandSession.java
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/commands/CommandSession.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/commands/CommandSession.java
new file mode 100644 (file)
index 0000000..8ad47b0
--- /dev/null
@@ -0,0 +1,640 @@
+package org.simantics.scl.compiler.commands;
+
+import gnu.trove.map.hash.THashMap;
+import gnu.trove.procedure.TObjectProcedure;
+import gnu.trove.set.hash.THashSet;
+
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.simantics.scl.compiler.common.names.Name;
+import org.simantics.scl.compiler.constants.StringConstant;
+import org.simantics.scl.compiler.elaboration.expressions.EApply;
+import org.simantics.scl.compiler.elaboration.expressions.EBlock;
+import org.simantics.scl.compiler.elaboration.expressions.EConstant;
+import org.simantics.scl.compiler.elaboration.expressions.EExternalConstant;
+import org.simantics.scl.compiler.elaboration.expressions.ELiteral;
+import org.simantics.scl.compiler.elaboration.expressions.EVariable;
+import org.simantics.scl.compiler.elaboration.expressions.Expression;
+import org.simantics.scl.compiler.elaboration.expressions.Variable;
+import org.simantics.scl.compiler.elaboration.expressions.block.GuardStatement;
+import org.simantics.scl.compiler.elaboration.expressions.block.Statement;
+import org.simantics.scl.compiler.environment.AbstractLocalEnvironment;
+import org.simantics.scl.compiler.environment.Environment;
+import org.simantics.scl.compiler.environment.LocalEnvironment;
+import org.simantics.scl.compiler.environment.specification.EnvironmentSpecification;
+import org.simantics.scl.compiler.errors.CompilationError;
+import org.simantics.scl.compiler.errors.Locations;
+import org.simantics.scl.compiler.internal.codegen.utils.NameMangling;
+import org.simantics.scl.compiler.internal.parsing.exceptions.SCLSyntaxErrorException;
+import org.simantics.scl.compiler.internal.parsing.parser.SCLParserImpl;
+import org.simantics.scl.compiler.internal.parsing.utils.LaxUTF8Reader;
+import org.simantics.scl.compiler.internal.parsing.utils.MemoReader;
+import org.simantics.scl.compiler.module.ImportDeclaration;
+import org.simantics.scl.compiler.module.repository.ImportFailure;
+import org.simantics.scl.compiler.module.repository.ImportFailureException;
+import org.simantics.scl.compiler.module.repository.ModuleRepository;
+import org.simantics.scl.compiler.runtime.RuntimeEnvironment;
+import org.simantics.scl.compiler.top.ExpressionEvaluator;
+import org.simantics.scl.compiler.top.LocalStorage;
+import org.simantics.scl.compiler.top.SCLExpressionCompilationException;
+import org.simantics.scl.compiler.types.TCon;
+import org.simantics.scl.compiler.types.Type;
+import org.simantics.scl.compiler.types.Types;
+import org.simantics.scl.runtime.SCLContext;
+import org.simantics.scl.runtime.function.Function;
+import org.simantics.scl.runtime.function.FunctionImpl2;
+import org.simantics.scl.runtime.reporting.DelegatingSCLReportingHandler;
+import org.simantics.scl.runtime.reporting.SCLReporting;
+import org.simantics.scl.runtime.reporting.SCLReportingHandler;
+import org.simantics.scl.runtime.tuple.Tuple0;
+
+
+public class CommandSession {
+
+    ModuleRepository moduleRepository;
+    SCLReportingHandler defaultHandler;
+    
+    RuntimeEnvironment runtimeEnvironment;
+    ValueToStringConverter valueToStringConverter;
+
+    ArrayList<CommandSessionImportEntry> importEntries = new ArrayList<CommandSessionImportEntry>();
+
+    THashMap<String,Object> variableValues = new THashMap<String,Object>();
+    THashMap<String,Type> variableTypes = new THashMap<String,Type>();
+    
+    PrintStream fileOutput;
+
+    private static final String CONTEXT_MODULE = "Expressions/Context";
+    private static final TCon CONTEXT_TYPE = Types.con(CONTEXT_MODULE, "Context");
+    private static final Name CONTEXT_GET = Name.create(CONTEXT_MODULE, "contextGet");
+
+    public CommandSession(ModuleRepository moduleRepository, SCLReportingHandler handler) {
+        this.moduleRepository = moduleRepository;
+        this.defaultHandler = new PrintDecorator(
+                handler == null ? SCLReportingHandler.DEFAULT : handler);
+        updateRuntimeEnvironment(true);
+    }
+    
+    private static EnvironmentSpecification createEnvironmentSpecification(Collection<CommandSessionImportEntry> importEntries) {
+        EnvironmentSpecification spec = new EnvironmentSpecification();
+        spec.importModule("Builtin", "");
+        spec.importModule("StandardLibrary", "");
+        spec.importModule("Expressions/Context", null);
+        for(CommandSessionImportEntry entry : importEntries)
+            if(!entry.disabled && !entry.hasError)
+                spec.importModule(entry.moduleName, entry.localName);
+        return spec;
+    }
+
+    public void updateRuntimeEnvironment(boolean clearErrorsFlags) {
+        if(clearErrorsFlags)
+            for(CommandSessionImportEntry entry : importEntries)
+                entry.hasError = false;
+        EnvironmentSpecification environmentSpecification = createEnvironmentSpecification(importEntries);
+        
+        runtimeEnvironment = null;
+        try {
+            try {
+                runtimeEnvironment = moduleRepository.createRuntimeEnvironment(
+                        environmentSpecification,
+                        getClass().getClassLoader());
+            } catch(ImportFailureException e) {
+                THashSet<String> failedModules = new THashSet<String>();
+                for(ImportFailure failure : e.failures) {
+                    failedModules.add(failure.moduleName);
+                    defaultHandler.printError(failure.toString());
+                    if(failure.reason instanceof CompilationError[])
+                        for(CompilationError error : (CompilationError[])failure.reason) {
+                            defaultHandler.printError("    " + error.description);
+                        }
+                }
+                for(CommandSessionImportEntry entry : importEntries)
+                    if(failedModules.contains(entry.moduleName))
+                        entry.hasError = true;
+                environmentSpecification = createEnvironmentSpecification(importEntries);
+                try {
+                    runtimeEnvironment = moduleRepository.createRuntimeEnvironment(
+                            environmentSpecification,
+                            getClass().getClassLoader());
+                } catch (ImportFailureException e1) {
+                    for(ImportFailure failure : e1.failures)
+                        defaultHandler.printError(failure.toString());
+                }
+            }
+        } catch(RuntimeException e) {
+            e.printStackTrace();
+            throw e;
+        }
+        valueToStringConverter = new ValueToStringConverter(runtimeEnvironment);
+    }
+    
+    public RuntimeEnvironment getRuntimeEnvironment() {
+        return runtimeEnvironment;
+    }
+
+    public ModuleRepository getModuleRepository() {
+        return moduleRepository;
+    }
+    
+    private static class CancelExecution extends RuntimeException {
+        private static final long serialVersionUID = -6925642906311538873L;
+    }
+
+    private LocalStorage localStorage = new LocalStorage() {
+        @Override
+        public void store(String name, Object value, Type type) {
+            variableValues.put(name, value);
+            variableTypes.put(name, type);
+        }
+    };
+    
+    private static class LocalFunction {
+        final Function function;
+        final Type type;
+        
+        public LocalFunction(Function function, Type type) {
+            this.function = function;
+            this.type = type;
+        }
+    }
+    
+    private static final THashMap<String, LocalFunction> LOCAL_FUNCTIONS = new THashMap<String, LocalFunction>();
+    static {
+        LOCAL_FUNCTIONS.put("runFromFile", new LocalFunction(new FunctionImpl2<CommandSession, String, Tuple0>() {
+            @Override
+            public Tuple0 apply(final CommandSession commandSession, String fileName) {
+                SCLContext context = SCLContext.getCurrent();
+                commandSession.runFromFile(fileName, (SCLReportingHandler)context.get(SCLReportingHandler.REPORTING_HANDLER));
+                return Tuple0.INSTANCE;
+            }
+        }, Types.functionE(Types.STRING, Types.PROC, Types.UNIT)));
+        LOCAL_FUNCTIONS.put("runTest", new LocalFunction(new FunctionImpl2<CommandSession, String, Tuple0>() {
+            @Override
+            public Tuple0 apply(final CommandSession commandSession, String fileName) {
+                SCLContext context = SCLContext.getCurrent();
+                SCLReportingHandler handler = (SCLReportingHandler)context.get(SCLReportingHandler.REPORTING_HANDLER);
+                try {
+                    BufferedReader reader = new BufferedReader(new LaxUTF8Reader(fileName));
+                    try {
+                        new TestScriptExecutor(commandSession, reader, handler).execute();
+                    } finally {
+                        reader.close();
+                    }
+                } catch(IOException e) {
+                    handler.printError(e.getMessage());
+                }
+                return Tuple0.INSTANCE;
+            }
+        }, Types.functionE(Types.STRING, Types.PROC, Types.UNIT)));
+        LOCAL_FUNCTIONS.put("reset", new LocalFunction(new FunctionImpl2<CommandSession, Tuple0, Tuple0>() {
+            @Override
+            public Tuple0 apply(CommandSession commandSession, Tuple0 _) {
+                commandSession.removeTransientImports();
+                commandSession.removeVariables();
+                commandSession.moduleRepository.getSourceRepository().checkUpdates();
+                commandSession.updateRuntimeEnvironment(true);
+                return Tuple0.INSTANCE;
+            }
+        }, Types.functionE(Types.UNIT, Types.PROC, Types.UNIT)));
+        LOCAL_FUNCTIONS.put("variables", new LocalFunction(new FunctionImpl2<CommandSession, Tuple0, List<String>>() {
+            @Override
+            public List<String> apply(CommandSession commandSession, Tuple0 _) {
+                ArrayList<String> result = new ArrayList<String>(commandSession.variableTypes.keySet());
+                Collections.sort(result);
+                return result;
+            }
+        }, Types.functionE(Types.PUNIT, Types.PROC, Types.list(Types.STRING))));
+        LOCAL_FUNCTIONS.put("startPrintingToFile", new LocalFunction(new FunctionImpl2<CommandSession, String, Tuple0>() {
+            @Override
+            public Tuple0 apply(final CommandSession commandSession, String fileName) {
+                try {
+                    if(commandSession.fileOutput != null) {
+                        commandSession.fileOutput.close();
+                        SCLReporting.printError("Printing to file was already enabled. Stopped the previous printing.");
+                    }
+                    commandSession.fileOutput = new PrintStream(fileName, "UTF-8");
+                } catch (FileNotFoundException e) {
+                    throw new RuntimeException(e);
+                } catch (UnsupportedEncodingException e) {
+                    throw new RuntimeException(e);
+                }
+                return Tuple0.INSTANCE;
+            }
+        }, Types.functionE(Types.STRING, Types.PROC, Types.UNIT)));
+        LOCAL_FUNCTIONS.put("startAppendingToFile", new LocalFunction(new FunctionImpl2<CommandSession, String, Tuple0>() {
+            @Override
+            public Tuple0 apply(final CommandSession commandSession, String fileName) {
+                try {
+                    if(commandSession.fileOutput != null) {
+                        commandSession.fileOutput.close();
+                        SCLReporting.printError("Printing to file was already enabled. Stopped the previous printing.");
+                    }
+                    FileOutputStream stream = new FileOutputStream(fileName, true);
+                    commandSession.fileOutput = new PrintStream(stream, false, "UTF-8");
+                } catch (FileNotFoundException e) {
+                    throw new RuntimeException(e);
+                } catch (UnsupportedEncodingException e) {
+                    throw new RuntimeException(e);
+                }
+                return Tuple0.INSTANCE;
+            }
+        }, Types.functionE(Types.STRING, Types.PROC, Types.UNIT)));
+        LOCAL_FUNCTIONS.put("stopPrintingToFile", new LocalFunction(new FunctionImpl2<CommandSession, Tuple0, Tuple0>() {
+            @Override
+            public Tuple0 apply(final CommandSession commandSession, Tuple0 _) {
+                if(commandSession.fileOutput != null) {
+                    commandSession.fileOutput.close();
+                    commandSession.fileOutput = null;
+                }
+                return Tuple0.INSTANCE;
+            }
+        }, Types.functionE(Types.PUNIT, Types.PROC, Types.UNIT)));
+    }
+
+    private LocalEnvironment createLocalEnvironment() {
+        return new AbstractLocalEnvironment() {
+            Variable contextVariable = new Variable("context", CONTEXT_TYPE);
+            @Override
+            public Expression resolve(Environment environment, String localName) {
+                Type type = variableTypes.get(localName);
+                if(type != null)
+                    return new EApply(
+                            new EConstant(environment.getValue(CONTEXT_GET), type),
+                            new EVariable(contextVariable),
+                            new ELiteral(new StringConstant(localName))
+                            );
+                LocalFunction localFunction = LOCAL_FUNCTIONS.get(localName);
+                if(localFunction != null) {
+                    return new EExternalConstant(
+                            localFunction.function.apply(CommandSession.this),
+                            localFunction.type);
+                }
+                return null;
+            }
+            @Override
+            protected Variable[] getContextVariables() {
+                return new Variable[] { contextVariable };
+            }
+            @Override
+            public void forNames(TObjectProcedure<String> proc) {
+                for(String name : variableTypes.keySet())
+                    proc.execute(name);
+                for(String name : LOCAL_FUNCTIONS.keySet())
+                    proc.execute(name);
+            }
+        };
+    }
+    
+    protected void removeTransientImports() {
+        ArrayList<CommandSessionImportEntry> newEntries = new ArrayList<CommandSessionImportEntry>(importEntries.size());
+        for(CommandSessionImportEntry entry : importEntries)
+            if(entry.persistent)
+                newEntries.add(entry);
+        importEntries = newEntries;
+    }
+
+    public THashMap<String,Type> localNamesForContentProposals() {
+        THashMap<String,Type> result = new THashMap<String,Type>();
+        for(Map.Entry<String,LocalFunction> entry : LOCAL_FUNCTIONS.entrySet())
+            result.put(entry.getKey(), entry.getValue().type);
+        result.putAll(variableTypes);
+        return result;
+    }
+    
+    private CompiledCommand compile(Expression expression) throws SCLExpressionCompilationException {
+        LocalEnvironment localEnvironment = createLocalEnvironment();
+        if(runtimeEnvironment == null)
+            throw new SCLExpressionCompilationException(new CompilationError[] {
+               new CompilationError("Compilation failed: imports in the current environment have failed.")
+            });
+        ExpressionEvaluator evaluator = new ExpressionEvaluator(runtimeEnvironment, localStorage, expression);
+        Function command = (Function)evaluator
+            .localEnvironment(localEnvironment)
+            .decorateExpression(true)
+            .eval();
+        return new CompiledCommand(command, evaluator.getType());
+    }
+    
+    class PrintDecorator extends DelegatingSCLReportingHandler {
+        public PrintDecorator(SCLReportingHandler baseHandler) {
+            super(baseHandler);
+        }
+
+        @Override
+        public void print(String text) {
+            super.print(text);
+            if(fileOutput != null)
+                fileOutput.println(text);
+        }
+        
+        @Override
+        public void printCommand(String command) {
+            super.printCommand(command);
+            if(fileOutput != null)
+                fileOutput.println("> " + command);
+        }
+        
+        @Override
+        public void printError(String error) {
+            super.printError(error);
+            if(fileOutput != null)
+                fileOutput.println(error);
+        }
+    }
+    
+    @SuppressWarnings("unchecked")
+    private void execute(MemoReader reader, Expression expression, final SCLReportingHandler handler) {
+        SCLContext context = SCLContext.getCurrent();
+        Object oldPrinter = context.put(SCLReportingHandler.REPORTING_HANDLER, handler);
+        try {
+            CompiledCommand command;
+            try {
+                handler.printCommand(reader.extractString(expression.location));
+                command = compile(expression);
+            } catch (SCLExpressionCompilationException e) {
+                CompilationError[] errors = ((SCLExpressionCompilationException)e).getErrors();
+                for(CompilationError error : errors) {
+                    if(error.location != Locations.NO_LOCATION)
+                        handler.printError(reader.locationUnderlining(error.location));
+                    handler.printError(error.description);
+                }
+                throw new CancelExecution();
+            }
+            reader.forgetEverythingBefore(Locations.endOf(expression.location));
+
+            Object resultValue = command.command.apply(variableValues);
+            String resultString = toString(resultValue, command.type);
+            if(!resultString.isEmpty())
+                handler.print(resultString);
+        } catch(Exception e) {
+            if(!(e instanceof CancelExecution)) {
+                if(e instanceof InterruptedException)
+                    handler.printError("Execution interrupted.");
+                else
+                    formatException(handler, e);
+            }
+            throw new CancelExecution();
+        } finally {
+            context.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
+        } 
+    }
+
+    private String toString(Object value, Type type) {
+        if(type.equals(Types.UNIT))
+            return "";
+        try {
+            return valueToStringConverter.show(value, type);
+        } catch (SCLExpressionCompilationException e) {
+            return "<value of type " + type + ">";
+        }
+    }
+    
+    class CommandParser extends SCLParserImpl {
+        SCLReportingHandler handler;
+        MemoReader reader; 
+        public CommandParser(SCLReportingHandler handler, MemoReader reader) {
+            super(reader);
+            this.reader = reader;
+            this.handler = handler;
+        }
+
+        EBlock currentBlock;
+        void finishBlock() {
+            if(currentBlock != null) {
+                checkInterrupted();
+                LinkedList<Statement> statements = currentBlock.getStatements();
+                currentBlock.location = Locations.combine(
+                        statements.getFirst().location,
+                        statements.getLast().location);
+                execute(reader, currentBlock, handler);
+                currentBlock = null;
+            }
+        }
+        @Override
+        protected Object reduceStatementCommand() {
+            Statement statement = (Statement)get(0);
+            if(statement.mayBeRecursive()) {
+                if(currentBlock == null)
+                    currentBlock = new EBlock();
+                currentBlock.addStatement(statement);
+            }
+            else {
+                finishBlock();
+                checkInterrupted();
+                if(statement instanceof GuardStatement)
+                    execute(reader, ((GuardStatement)statement).value, handler);
+                else {
+                    EBlock block = new EBlock();
+                    block.addStatement(statement);
+                    block.location = statement.location;
+                    execute(reader, block, handler);
+                }
+            }
+            return null;
+        }
+        
+        @Override
+        protected Object reduceImportCommand() {
+            finishBlock();
+            checkInterrupted();
+            
+            ImportDeclaration importDeclaration = (ImportDeclaration)get(0);
+            handler.printCommand(reader.extractString(importDeclaration.location));
+            new CommandSessionImportEntry(importDeclaration.moduleName,
+                    importDeclaration.localName).addTo(importEntries);
+            updateRuntimeEnvironment(false);
+            return null;
+        }
+    }
+    
+    private void checkInterrupted() {
+        if(Thread.interrupted()) {
+            defaultHandler.printError("Execution interrupted.");
+            throw new CancelExecution();
+        }
+    }
+    
+    public void execute(Reader commandReader, SCLReportingHandler handler) {
+        if(handler == null)
+            handler = defaultHandler;
+        else if (!(handler instanceof PrintDecorator))
+            handler = new PrintDecorator(handler);
+        CommandParser parser = new CommandParser(handler, new MemoReader(commandReader));
+        try {
+            parser.parseCommands();
+            parser.finishBlock();
+        } catch(CancelExecution e) {
+        } catch(SCLSyntaxErrorException e) {
+            handler.printCommand(parser.reader.getLastCommand());
+            if(e.location != Locations.NO_LOCATION)
+                handler.printError(parser.reader.locationUnderlining(e.location));
+            handler.printError(e.getMessage());
+        } catch(Exception e) {
+            if(e instanceof InterruptedException)
+                handler.printError("Execution interrupted.");
+            else
+                formatException(handler, e);
+        }
+    }
+    
+    public void execute(String command) {
+        execute(new StringReader(command), null);
+    }
+    
+    public void execute(String command, SCLReportingHandler handler) {
+        execute(new StringReader(command), handler);
+    }
+
+    public CompilationError[] validate(String command) {
+        return CompilationError.EMPTY_ARRAY;
+        /*try {
+            compile(command);
+            return CompilationError.EMPTY_ARRAY;
+        } catch(SCLExpressionCompilationException e) {
+            return e.getErrors();
+        }*/
+    }
+
+    private static final String THIS_CLASS_NAME = CommandSession.class.getName(); 
+
+    public static void formatException(
+            SCLReportingHandler handler, 
+            Throwable e) {
+        formatException(handler, null, e);
+    }
+            
+    private static void formatException(
+            SCLReportingHandler handler, 
+            StackTraceElement[] enclosingTrace, 
+            Throwable e) {
+        StackTraceElement[] elements = e.getStackTrace();
+        Throwable cause = e.getCause();
+        if(cause != null) {
+            formatException(handler, elements, cause);
+            handler.printError("Rethrown as ");
+        }
+        handler.printError(e.toString());
+        int endPos = elements.length;
+        if(enclosingTrace != null) {
+            int p = enclosingTrace.length;
+            while(endPos > 0 && p > 0 && elements[endPos-1].equals(enclosingTrace[p-1])) {
+                --p;
+                --endPos;
+            }
+        }
+        else {
+            for(int i=0;i<endPos;++i) {
+                StackTraceElement element = elements[i];
+                if(element.getMethodName().equals("execute") &&
+                        element.getClassName().equals(THIS_CLASS_NAME)) {
+                    endPos = i;
+                    while(endPos > 0) {
+                        element = elements[endPos-1];
+                        String className = element.getClassName(); 
+                        if(className.startsWith("org.simantics.scl.compiler.top.SCLExpressionCompiler")
+                                //|| element.getClassName().startsWith("org.simantics.scl.compiler.interpreted.")
+                                || className.startsWith("org.simantics.scl.runtime.function.FunctionImpl")
+                                //|| className.startsWith("tempsclpackage")
+                                )
+                            --endPos;
+                        else
+                            break;
+                    }
+                    break;
+                }
+            }
+        }
+        for(int i=0;i<endPos;++i) {
+            StringBuilder b = new StringBuilder();
+            StackTraceElement element = elements[i];
+            String className = element.getClassName(); 
+            if(className.equals("org.simantics.scl.compiler.interpreted.IApply")
+                    || className.equals("org.simantics.scl.compiler.interpreted.ILet")
+                    || className.startsWith("tempsclpackage"))
+                continue;
+            if(className.startsWith("org.simantics.scl.compiler.interpreted.ILambda")) {
+                b.append("\tat command line\n");
+                continue;
+            }
+            String methodName = element.getMethodName(); 
+            if(className.startsWith("org.simantics.scl.runtime.function.FunctionImpl") &&
+                    methodName.equals("applyArray"))
+                continue;
+            String fileName = element.getFileName();
+            if("_SCL_Closure".equals(fileName))
+                continue;
+            b.append("\tat ");
+            if("_SCL_Module".equals(fileName)
+                    || "_SCL_TypeClassInstance".equals(fileName))
+                b.append(NameMangling.demangle(methodName))
+                .append('(').append(element.getLineNumber()).append(')');
+            else
+                b.append(element);
+            handler.printError(b.toString());
+        }
+    }
+    
+    public void setVariable(String name, Type type, Object value) {
+        variableValues.put(name, value);
+        variableTypes.put(name, type);
+    }
+
+    public Object getVariableValue(String name) {
+        return variableValues.get(name);
+    }
+    
+    public Type getVariableType(String name) {
+        return variableTypes.get(name);
+    }
+    
+    public void removeVariable(String name) {
+       variableValues.remove(name);
+       variableTypes.remove(name);
+    }
+    
+    public void removeVariables() {
+       variableValues.clear();
+       variableTypes.clear();
+    }
+
+    public Set<String> getVariables() {
+        return variableTypes.keySet();
+    }
+    
+    public ArrayList<CommandSessionImportEntry> getImportEntries() {
+        return importEntries;
+    }
+    
+    public void setImportEntries(
+            ArrayList<CommandSessionImportEntry> importEntries) {
+        this.importEntries = importEntries;
+        updateRuntimeEnvironment(true);
+    }
+
+    public void runFromFile(String fileName, SCLReportingHandler handler) {
+        try {
+            Reader reader = new LaxUTF8Reader(fileName);
+            try {
+                execute(reader, handler);
+            } finally {
+                reader.close();
+            }
+        } catch(IOException e) {
+            formatException(handler, e);
+        }
+    }
+}