d0e44a9c7b263a36c0a75b60cc5f678432081165
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / commands / CommandSession.java
1 package org.simantics.scl.compiler.commands;
2
3 import java.io.BufferedReader;
4 import java.io.FileNotFoundException;
5 import java.io.FileOutputStream;
6 import java.io.IOException;
7 import java.io.PrintStream;
8 import java.io.Reader;
9 import java.io.StringReader;
10 import java.io.UnsupportedEncodingException;
11 import java.util.ArrayList;
12 import java.util.Collection;
13 import java.util.Collections;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Set;
17
18 import org.simantics.scl.compiler.common.names.Names;
19 import org.simantics.scl.compiler.constants.StringConstant;
20 import org.simantics.scl.compiler.elaboration.expressions.EApply;
21 import org.simantics.scl.compiler.elaboration.expressions.EBlock;
22 import org.simantics.scl.compiler.elaboration.expressions.EConstant;
23 import org.simantics.scl.compiler.elaboration.expressions.EExternalConstant;
24 import org.simantics.scl.compiler.elaboration.expressions.ELiteral;
25 import org.simantics.scl.compiler.elaboration.expressions.EVariable;
26 import org.simantics.scl.compiler.elaboration.expressions.Expression;
27 import org.simantics.scl.compiler.elaboration.expressions.Variable;
28 import org.simantics.scl.compiler.elaboration.expressions.block.GuardStatement;
29 import org.simantics.scl.compiler.elaboration.expressions.block.Statement;
30 import org.simantics.scl.compiler.environment.AbstractLocalEnvironment;
31 import org.simantics.scl.compiler.environment.Environment;
32 import org.simantics.scl.compiler.environment.LocalEnvironment;
33 import org.simantics.scl.compiler.environment.specification.EnvironmentSpecification;
34 import org.simantics.scl.compiler.errors.CompilationError;
35 import org.simantics.scl.compiler.errors.ErrorSeverity;
36 import org.simantics.scl.compiler.errors.Locations;
37 import org.simantics.scl.compiler.internal.codegen.utils.NameMangling;
38 import org.simantics.scl.compiler.internal.parsing.exceptions.SCLSyntaxErrorException;
39 import org.simantics.scl.compiler.internal.parsing.parser.SCLParserImpl;
40 import org.simantics.scl.compiler.internal.parsing.utils.LaxUTF8Reader;
41 import org.simantics.scl.compiler.internal.parsing.utils.MemoReader;
42 import org.simantics.scl.compiler.module.ImportDeclaration;
43 import org.simantics.scl.compiler.module.repository.ImportFailure;
44 import org.simantics.scl.compiler.module.repository.ImportFailureException;
45 import org.simantics.scl.compiler.module.repository.ModuleRepository;
46 import org.simantics.scl.compiler.module.repository.UpdateListener;
47 import org.simantics.scl.compiler.runtime.RuntimeEnvironment;
48 import org.simantics.scl.compiler.top.ExpressionEvaluator;
49 import org.simantics.scl.compiler.top.LocalStorage;
50 import org.simantics.scl.compiler.top.SCLExpressionCompilationException;
51 import org.simantics.scl.compiler.types.Type;
52 import org.simantics.scl.compiler.types.Types;
53 import org.simantics.scl.runtime.SCLContext;
54 import org.simantics.scl.runtime.function.Function;
55 import org.simantics.scl.runtime.function.FunctionImpl2;
56 import org.simantics.scl.runtime.reporting.DelegatingSCLReportingHandler;
57 import org.simantics.scl.runtime.reporting.SCLReporting;
58 import org.simantics.scl.runtime.reporting.SCLReportingHandler;
59 import org.simantics.scl.runtime.tuple.Tuple0;
60
61 import gnu.trove.map.hash.THashMap;
62 import gnu.trove.procedure.TObjectProcedure;
63 import gnu.trove.set.hash.THashSet;
64
65
66 public class CommandSession {
67
68     ModuleRepository moduleRepository;
69     SCLReportingHandler defaultHandler;
70     
71     RuntimeEnvironment runtimeEnvironment;
72     ValueToStringConverter valueToStringConverter;
73
74     ArrayList<CommandSessionImportEntry> importEntries = new ArrayList<CommandSessionImportEntry>();
75
76     THashMap<String,Object> variableValues = new THashMap<String,Object>();
77     THashMap<String,Type> variableTypes = new THashMap<String,Type>();
78     
79     PrintStream fileOutput;
80     private UpdateListener dependenciesListener;
81     
82     /**
83      * Only checks the commands for compilation errors but does not run them.
84      */
85     private boolean validateOnly; 
86     
87     public CommandSession(ModuleRepository moduleRepository, SCLReportingHandler handler) {
88         this.moduleRepository = moduleRepository;
89         this.defaultHandler = new PrintDecorator(
90                 handler == null ? SCLReportingHandler.DEFAULT : handler);
91         updateRuntimeEnvironment(true);
92     }
93     
94     private static EnvironmentSpecification createEnvironmentSpecification(Collection<CommandSessionImportEntry> importEntries) {
95         EnvironmentSpecification spec = new EnvironmentSpecification();
96         spec.importModule("Builtin", "");
97         spec.importModule("StandardLibrary", "");
98         spec.importModule("Expressions/Context", null);
99         for(CommandSessionImportEntry entry : importEntries)
100             if(!entry.disabled && !entry.hasError)
101                 spec.importModule(entry.moduleName, entry.localName);
102         return spec;
103     }
104
105     public void updateRuntimeEnvironment(boolean clearErrorsFlags) {
106         if(clearErrorsFlags)
107             for(CommandSessionImportEntry entry : importEntries)
108                 entry.hasError = false;
109         EnvironmentSpecification environmentSpecification = createEnvironmentSpecification(importEntries);
110         
111         runtimeEnvironment = null;
112         try {
113             if(dependenciesListener != null)
114                 dependenciesListener.stopListening();
115             try {
116                 runtimeEnvironment = moduleRepository.createRuntimeEnvironment(
117                         environmentSpecification,
118                         getClass().getClassLoader(),
119                         dependenciesListener);
120             } catch(ImportFailureException e) {
121                 THashSet<String> failedModules = new THashSet<String>();
122                 for(ImportFailure failure : e.failures) {
123                     failedModules.add(failure.moduleName);
124                     defaultHandler.printError(failure.toString());
125                     if(failure.reason instanceof CompilationError[])
126                         for(CompilationError error : (CompilationError[])failure.reason) {
127                             if(error.severity != ErrorSeverity.WARNING)
128                                 defaultHandler.printError("    " + error.description);
129                         }
130                 }
131                 for(CommandSessionImportEntry entry : importEntries)
132                     if(failedModules.contains(entry.moduleName))
133                         entry.hasError = true;
134                 environmentSpecification = createEnvironmentSpecification(importEntries);
135                 try {
136                     runtimeEnvironment = moduleRepository.createRuntimeEnvironment(
137                             environmentSpecification,
138                             getClass().getClassLoader()); // no listener here, because should listen also failed modules
139                 } catch (ImportFailureException e1) {
140                     for(ImportFailure failure : e1.failures)
141                         defaultHandler.printError(failure.toString());
142                 }
143             }
144         } catch(RuntimeException e) {
145             e.printStackTrace();
146             throw e;
147         }
148         valueToStringConverter = new ValueToStringConverter(runtimeEnvironment);
149     }
150     
151     public RuntimeEnvironment getRuntimeEnvironment() {
152         return runtimeEnvironment;
153     }
154
155     public ModuleRepository getModuleRepository() {
156         return moduleRepository;
157     }
158     
159     private static class CancelExecution extends RuntimeException {
160         private static final long serialVersionUID = -6925642906311538873L;
161     }
162
163     private LocalStorage localStorage = new LocalStorage() {
164         @Override
165         public void store(String name, Object value, Type type) {
166             variableValues.put(name, value);
167             variableTypes.put(name, type);
168         }
169     };
170     
171     private static class LocalFunction {
172         final Function function;
173         final Type type;
174         
175         public LocalFunction(Function function, Type type) {
176             this.function = function;
177             this.type = type;
178         }
179     }
180     
181     private static final THashMap<String, LocalFunction> LOCAL_FUNCTIONS = new THashMap<String, LocalFunction>();
182     static {
183         LOCAL_FUNCTIONS.put("runFromFile", new LocalFunction(new FunctionImpl2<CommandSession, String, Tuple0>() {
184             @Override
185             public Tuple0 apply(final CommandSession commandSession, String fileName) {
186                 SCLContext context = SCLContext.getCurrent();
187                 commandSession.runFromFile(fileName, (SCLReportingHandler)context.get(SCLReportingHandler.REPORTING_HANDLER));
188                 return Tuple0.INSTANCE;
189             }
190         }, Types.functionE(Types.STRING, Types.PROC, Types.UNIT)));
191         LOCAL_FUNCTIONS.put("runTest", new LocalFunction(new FunctionImpl2<CommandSession, String, Tuple0>() {
192             @Override
193             public Tuple0 apply(final CommandSession commandSession, String fileName) {
194                 SCLContext context = SCLContext.getCurrent();
195                 SCLReportingHandler handler = (SCLReportingHandler)context.get(SCLReportingHandler.REPORTING_HANDLER);
196                 try {
197                     BufferedReader reader = new BufferedReader(new LaxUTF8Reader(fileName));
198                     try {
199                         new TestScriptExecutor(commandSession, reader, handler).execute();
200                     } finally {
201                         reader.close();
202                     }
203                 } catch(IOException e) {
204                     handler.printError(e.getMessage());
205                 }
206                 return Tuple0.INSTANCE;
207             }
208         }, Types.functionE(Types.STRING, Types.PROC, Types.UNIT)));
209         LOCAL_FUNCTIONS.put("reset", new LocalFunction(new FunctionImpl2<CommandSession, Tuple0, Tuple0>() {
210             @Override
211             public Tuple0 apply(CommandSession commandSession, Tuple0 dummy) {
212                 commandSession.removeTransientImports();
213                 commandSession.removeVariables();
214                 commandSession.moduleRepository.getSourceRepository().checkUpdates();
215                 commandSession.updateRuntimeEnvironment(true);
216                 return Tuple0.INSTANCE;
217             }
218         }, Types.functionE(Types.UNIT, Types.PROC, Types.UNIT)));
219         LOCAL_FUNCTIONS.put("variables", new LocalFunction(new FunctionImpl2<CommandSession, Tuple0, List<String>>() {
220             @Override
221             public List<String> apply(CommandSession commandSession, Tuple0 dummy) {
222                 ArrayList<String> result = new ArrayList<String>(commandSession.variableTypes.keySet());
223                 Collections.sort(result);
224                 return result;
225             }
226         }, Types.functionE(Types.PUNIT, Types.PROC, Types.list(Types.STRING))));
227         LOCAL_FUNCTIONS.put("startPrintingToFile", new LocalFunction(new FunctionImpl2<CommandSession, String, Tuple0>() {
228             @Override
229             public Tuple0 apply(final CommandSession commandSession, String fileName) {
230                 try {
231                     if(commandSession.fileOutput != null) {
232                         commandSession.fileOutput.close();
233                         SCLReporting.printError("Printing to file was already enabled. Stopped the previous printing.");
234                     }
235                     commandSession.fileOutput = new PrintStream(fileName, "UTF-8");
236                 } catch (FileNotFoundException e) {
237                     throw new RuntimeException(e);
238                 } catch (UnsupportedEncodingException e) {
239                     throw new RuntimeException(e);
240                 }
241                 return Tuple0.INSTANCE;
242             }
243         }, Types.functionE(Types.STRING, Types.PROC, Types.UNIT)));
244         LOCAL_FUNCTIONS.put("startAppendingToFile", new LocalFunction(new FunctionImpl2<CommandSession, String, Tuple0>() {
245             @Override
246             public Tuple0 apply(final CommandSession commandSession, String fileName) {
247                 try {
248                     if(commandSession.fileOutput != null) {
249                         commandSession.fileOutput.close();
250                         SCLReporting.printError("Printing to file was already enabled. Stopped the previous printing.");
251                     }
252                     FileOutputStream stream = new FileOutputStream(fileName, true);
253                     commandSession.fileOutput = new PrintStream(stream, false, "UTF-8");
254                 } catch (FileNotFoundException e) {
255                     throw new RuntimeException(e);
256                 } catch (UnsupportedEncodingException e) {
257                     throw new RuntimeException(e);
258                 }
259                 return Tuple0.INSTANCE;
260             }
261         }, Types.functionE(Types.STRING, Types.PROC, Types.UNIT)));
262         LOCAL_FUNCTIONS.put("stopPrintingToFile", new LocalFunction(new FunctionImpl2<CommandSession, Tuple0, Tuple0>() {
263             @Override
264             public Tuple0 apply(final CommandSession commandSession, Tuple0 dummy) {
265                 if(commandSession.fileOutput != null) {
266                     commandSession.fileOutput.close();
267                     commandSession.fileOutput = null;
268                 }
269                 return Tuple0.INSTANCE;
270             }
271         }, Types.functionE(Types.PUNIT, Types.PROC, Types.UNIT)));
272     }
273
274     private LocalEnvironment createLocalEnvironment() {
275         return new AbstractLocalEnvironment() {
276             Variable contextVariable = new Variable("context", Names.Expressions_Context_Context);
277             @Override
278             public Expression resolve(Environment environment, String localName) {
279                 Type type = variableTypes.get(localName);
280                 if(type != null)
281                     return new EApply(
282                             new EConstant(environment.getValue(Names.Expressions_Context_contextGet), type),
283                             new EVariable(contextVariable),
284                             new ELiteral(new StringConstant(localName))
285                             );
286                 LocalFunction localFunction = LOCAL_FUNCTIONS.get(localName);
287                 if(localFunction != null) {
288                     return new EExternalConstant(
289                             localFunction.function.apply(CommandSession.this),
290                             localFunction.type);
291                 }
292                 return null;
293             }
294             @Override
295             protected Variable[] getContextVariables() {
296                 return new Variable[] { contextVariable };
297             }
298             @Override
299             public void forNames(TObjectProcedure<String> proc) {
300                 for(String name : variableTypes.keySet())
301                     proc.execute(name);
302                 for(String name : LOCAL_FUNCTIONS.keySet())
303                     proc.execute(name);
304             }
305         };
306     }
307     
308     protected void removeTransientImports() {
309         ArrayList<CommandSessionImportEntry> newEntries = new ArrayList<CommandSessionImportEntry>(importEntries.size());
310         for(CommandSessionImportEntry entry : importEntries)
311             if(entry.persistent)
312                 newEntries.add(entry);
313         importEntries = newEntries;
314     }
315
316     public THashMap<String,Type> localNamesForContentProposals() {
317         THashMap<String,Type> result = new THashMap<String,Type>();
318         for(Map.Entry<String,LocalFunction> entry : LOCAL_FUNCTIONS.entrySet())
319             result.put(entry.getKey(), entry.getValue().type);
320         result.putAll(variableTypes);
321         return result;
322     }
323     
324     private CompiledCommand compile(Expression expression) throws SCLExpressionCompilationException {
325         LocalEnvironment localEnvironment = createLocalEnvironment();
326         if(runtimeEnvironment == null)
327             throw new SCLExpressionCompilationException(new CompilationError[] {
328                new CompilationError("Compilation failed: imports in the current environment have failed.")
329             });
330         ExpressionEvaluator evaluator = new ExpressionEvaluator(runtimeEnvironment, localStorage, expression);
331         Function command = (Function)evaluator
332             .localEnvironment(localEnvironment)
333             .decorateExpression(true)
334             .validateOnly(validateOnly)
335             .eval();
336         return new CompiledCommand(command, evaluator.getType());
337     }
338     
339     class PrintDecorator extends DelegatingSCLReportingHandler {
340         public PrintDecorator(SCLReportingHandler baseHandler) {
341             super(baseHandler);
342         }
343
344         @Override
345         public void print(String text) {
346             super.print(text);
347             if(fileOutput != null)
348                 fileOutput.println(text);
349         }
350         
351         @Override
352         public void printCommand(String command) {
353             super.printCommand(command);
354             if(fileOutput != null)
355                 fileOutput.println("> " + command);
356         }
357         
358         @Override
359         public void printError(String error) {
360             super.printError(error);
361             if(fileOutput != null)
362                 fileOutput.println(error);
363         }
364     }
365     
366     @SuppressWarnings("unchecked")
367     private void execute(MemoReader reader, Expression expression, final SCLReportingHandler handler) {
368         SCLContext context = SCLContext.getCurrent();
369         Object oldPrinter = context.put(SCLReportingHandler.REPORTING_HANDLER, handler);
370         try {
371             CompiledCommand command;
372             try {
373                 handler.printCommand(reader.extractString(expression.location));
374                 command = compile(expression);
375             } catch (SCLExpressionCompilationException e) {
376                 if(validateOnly)
377                     throw e;
378                 CompilationError[] errors = e.getErrors();
379                 for(CompilationError error : errors) {
380                     if(error.location != Locations.NO_LOCATION)
381                         handler.printError(reader.locationUnderlining(error.location));
382                     handler.printError(error.description);
383                 }
384                 throw new CancelExecution();
385             }
386             reader.forgetEverythingBefore(Locations.endOf(expression.location));
387
388             if(!validateOnly) {
389                 Object resultValue = command.command.apply(variableValues);
390                 String resultString = toString(resultValue, command.type);
391                 if(!resultString.isEmpty())
392                     handler.print(resultString);
393             }
394         } catch(Exception e) {
395             if(validateOnly)
396                 throw e;
397             if(!(e instanceof CancelExecution)) {
398                 if(e instanceof InterruptedException)
399                     handler.printError("Execution interrupted.");
400                 else
401                     formatException(handler, e);
402             }
403             throw new CancelExecution();
404         } finally {
405             context.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
406         } 
407     }
408
409     private String toString(Object value, Type type) {
410         if(type.equals(Types.UNIT))
411             return "";
412         try {
413             return valueToStringConverter.show(value, type);
414         } catch (SCLExpressionCompilationException e) {
415             return "<value of type " + type + ">";
416         }
417     }
418     
419     class CommandParser extends SCLParserImpl {
420         SCLReportingHandler handler;
421         MemoReader reader; 
422         public CommandParser(SCLReportingHandler handler, MemoReader reader) {
423             super(reader);
424             this.reader = reader;
425             this.handler = handler;
426         }
427
428         EBlock currentBlock;
429         void finishBlock() {
430             if(currentBlock != null) {
431                 checkInterrupted();
432                 currentBlock.location = Locations.combine(
433                         currentBlock.getFirst().location,
434                         currentBlock.getLast().location);
435                 execute(reader, currentBlock, handler);
436                 currentBlock = null;
437             }
438         }
439         @Override
440         protected Object reduceStatementCommand() {
441             Statement statement = (Statement)get(0);
442             if(statement.mayBeRecursive()) {
443                 if(currentBlock == null)
444                     currentBlock = new EBlock();
445                 currentBlock.addStatement(statement);
446             }
447             else {
448                 finishBlock();
449                 checkInterrupted();
450                 if(statement instanceof GuardStatement)
451                     execute(reader, ((GuardStatement)statement).value, handler);
452                 else {
453                     EBlock block = new EBlock();
454                     block.addStatement(statement);
455                     block.location = statement.location;
456                     execute(reader, block, handler);
457                 }
458             }
459             return null;
460         }
461         
462         @Override
463         protected Object reduceImportCommand() {
464             finishBlock();
465             checkInterrupted();
466             
467             ImportDeclaration importDeclaration = (ImportDeclaration)get(0);
468             handler.printCommand(reader.extractString(importDeclaration.location));
469             new CommandSessionImportEntry(importDeclaration.moduleName,
470                     importDeclaration.localName).addTo(importEntries);
471             updateRuntimeEnvironment(false);
472             return null;
473         }
474     }
475     
476     private void checkInterrupted() {
477         if(Thread.interrupted()) {
478             defaultHandler.printError("Execution interrupted.");
479             throw new CancelExecution();
480         }
481     }
482     
483     private CompilationError[] validate(Reader commandReader) {
484         CommandParser parser = new CommandParser(defaultHandler, new MemoReader(commandReader));
485         validateOnly = true;
486         try {
487             parser.parseCommands();
488             parser.finishBlock();
489             return CompilationError.EMPTY_ARRAY;
490         } catch(SCLExpressionCompilationException e) {
491             return e.getErrors();
492         } catch(SCLSyntaxErrorException e) {
493             return new CompilationError[] { new CompilationError(e.location, e.getMessage()) };
494         } catch(Exception e) {
495             return new CompilationError[] { new CompilationError(Locations.NO_LOCATION, e.getMessage()) };
496         } finally {
497             validateOnly = false;
498         }
499     }
500     
501     public void execute(Reader commandReader, SCLReportingHandler handler) {
502         if(handler == null)
503             handler = defaultHandler;
504         else if (!(handler instanceof PrintDecorator))
505             handler = new PrintDecorator(handler);
506         CommandParser parser = new CommandParser(handler, new MemoReader(commandReader));
507         try {
508             parser.parseCommands();
509             parser.finishBlock();
510         } catch(CancelExecution e) {
511         } catch(SCLSyntaxErrorException e) {
512             handler.printCommand(parser.reader.getLastCommand());
513             if(e.location != Locations.NO_LOCATION)
514                 handler.printError(parser.reader.locationUnderlining(e.location));
515             handler.printError(e.getMessage());
516         } catch (Exception | AssertionError e) {
517             if(e instanceof InterruptedException)
518                 handler.printError("Execution interrupted.");
519             else
520                 formatException(handler, e);
521         }
522     }
523     
524     public void execute(String command) {
525         execute(new StringReader(command), null);
526     }
527     
528     public void execute(String command, SCLReportingHandler handler) {
529         execute(new StringReader(command), handler);
530     }
531
532     private static final String THIS_CLASS_NAME = CommandSession.class.getName(); 
533
534     public static void formatException(
535             SCLReportingHandler handler, 
536             Throwable e) {
537         formatException(handler, null, e);
538     }
539             
540     private static void formatException(
541             SCLReportingHandler handler, 
542             StackTraceElement[] enclosingTrace, 
543             Throwable e) {
544         StackTraceElement[] elements = e.getStackTrace();
545         Throwable cause = e.getCause();
546         if(cause != null) {
547             formatException(handler, elements, cause);
548             handler.printError("Rethrown as ");
549         }
550         handler.printError(e.toString());
551         int endPos = elements.length;
552         if(enclosingTrace != null) {
553             int p = enclosingTrace.length;
554             while(endPos > 0 && p > 0 && elements[endPos-1].equals(enclosingTrace[p-1])) {
555                 --p;
556                 --endPos;
557             }
558         }
559         else {
560             for(int i=0;i<endPos;++i) {
561                 StackTraceElement element = elements[i];
562                 if(element.getMethodName().equals("execute") &&
563                         element.getClassName().equals(THIS_CLASS_NAME)) {
564                     endPos = i;
565                     while(endPos > 0) {
566                         element = elements[endPos-1];
567                         String className = element.getClassName(); 
568                         if(className.startsWith("org.simantics.scl.compiler.top.SCLExpressionCompiler")
569                                 //|| element.getClassName().startsWith("org.simantics.scl.compiler.interpreted.")
570                                 || className.startsWith("org.simantics.scl.runtime.function.FunctionImpl")
571                                 //|| className.startsWith("tempsclpackage")
572                                 )
573                             --endPos;
574                         else
575                             break;
576                     }
577                     break;
578                 }
579             }
580         }
581         for(int i=0;i<endPos;++i) {
582             StringBuilder b = new StringBuilder();
583             StackTraceElement element = elements[i];
584             String className = element.getClassName(); 
585             if(className.equals("org.simantics.scl.compiler.interpreted.IApply")
586                     || className.equals("org.simantics.scl.compiler.interpreted.ILet")
587                     || className.startsWith("tempsclpackage"))
588                 continue;
589             if(className.startsWith("org.simantics.scl.compiler.interpreted.ILambda")) {
590                 b.append("\tat command line\n");
591                 continue;
592             }
593             String methodName = element.getMethodName(); 
594             if(className.startsWith("org.simantics.scl.runtime.function.FunctionImpl") &&
595                     methodName.equals("applyArray"))
596                 continue;
597             String fileName = element.getFileName();
598             if("_SCL_Closure".equals(fileName))
599                 continue;
600             b.append("\tat ");
601             if("_SCL_Module".equals(fileName)
602                     || "_SCL_TypeClassInstance".equals(fileName))
603                 b.append(className)
604                 .append('.')
605                 .append(NameMangling.demangle(methodName))
606                 .append('(').append(element.getLineNumber()).append(')');
607             else
608                 b.append(element);
609             handler.printError(b.toString());
610         }
611     }
612     
613     public void setVariable(String name, Type type, Object value) {
614         variableValues.put(name, value);
615         variableTypes.put(name, type);
616     }
617
618     public Object getVariableValue(String name) {
619         return variableValues.get(name);
620     }
621     
622     public Type getVariableType(String name) {
623         return variableTypes.get(name);
624     }
625     
626     public void removeVariable(String name) {
627         variableValues.remove(name);
628         variableTypes.remove(name);
629     }
630     
631     public void removeVariables() {
632         variableValues.clear();
633         variableTypes.clear();
634     }
635
636     public Set<String> getVariables() {
637         return variableTypes.keySet();
638     }
639     
640     public ArrayList<CommandSessionImportEntry> getImportEntries() {
641         return importEntries;
642     }
643     
644     public void setImportEntries(
645             ArrayList<CommandSessionImportEntry> importEntries) {
646         this.importEntries = importEntries;
647         updateRuntimeEnvironment(true);
648     }
649
650     public void runFromFile(String fileName, SCLReportingHandler handler) {
651         try {
652             Reader reader = new LaxUTF8Reader(fileName);
653             try {
654                 execute(reader, handler);
655             } finally {
656                 reader.close();
657             }
658         } catch(IOException e) {
659             formatException(handler, e);
660         }
661     }
662
663     public static CompilationError[] validate(ModuleRepository moduleRepository,StringReader commandReader) {
664         CommandSession session = new CommandSession(moduleRepository, null);
665         return session.validate(commandReader);
666     }
667     
668     public static CompilationError[] validate(ModuleRepository moduleRepository,String command) {
669         return validate(moduleRepository, new StringReader(command));
670     }
671
672     public CompilationError[] validate(String command) {
673         return validate(new StringReader(command));
674     }
675
676     public void setDependenciesListener(UpdateListener dependenciesListener) {
677         this.dependenciesListener = dependenciesListener;
678     }
679 }