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