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