Expose CommandSession in SCL
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / commands / CommandSession.java
index e463a4e6a4ca420c8308e405c4dc0017dd321d8c..00a7714a63640a3f2ae31bd29df0625c7f455ff4 100644 (file)
@@ -11,13 +11,13 @@ import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import org.simantics.scl.compiler.common.names.Name;
+import org.simantics.scl.compiler.common.names.Names;
 import org.simantics.scl.compiler.constants.StringConstant;
+import org.simantics.scl.compiler.dynamic.SafeDynamic;
 import org.simantics.scl.compiler.elaboration.expressions.EApply;
 import org.simantics.scl.compiler.elaboration.expressions.EBlock;
 import org.simantics.scl.compiler.elaboration.expressions.EConstant;
@@ -33,6 +33,7 @@ import org.simantics.scl.compiler.environment.Environment;
 import org.simantics.scl.compiler.environment.LocalEnvironment;
 import org.simantics.scl.compiler.environment.specification.EnvironmentSpecification;
 import org.simantics.scl.compiler.errors.CompilationError;
+import org.simantics.scl.compiler.errors.ErrorSeverity;
 import org.simantics.scl.compiler.errors.Locations;
 import org.simantics.scl.compiler.internal.codegen.utils.NameMangling;
 import org.simantics.scl.compiler.internal.parsing.exceptions.SCLSyntaxErrorException;
@@ -43,11 +44,11 @@ import org.simantics.scl.compiler.module.ImportDeclaration;
 import org.simantics.scl.compiler.module.repository.ImportFailure;
 import org.simantics.scl.compiler.module.repository.ImportFailureException;
 import org.simantics.scl.compiler.module.repository.ModuleRepository;
+import org.simantics.scl.compiler.module.repository.UpdateListener;
 import org.simantics.scl.compiler.runtime.RuntimeEnvironment;
 import org.simantics.scl.compiler.top.ExpressionEvaluator;
 import org.simantics.scl.compiler.top.LocalStorage;
 import org.simantics.scl.compiler.top.SCLExpressionCompilationException;
-import org.simantics.scl.compiler.types.TCon;
 import org.simantics.scl.compiler.types.Type;
 import org.simantics.scl.compiler.types.Types;
 import org.simantics.scl.runtime.SCLContext;
@@ -77,10 +78,16 @@ public class CommandSession {
     THashMap<String,Type> variableTypes = new THashMap<String,Type>();
     
     PrintStream fileOutput;
-
-    private static final String CONTEXT_MODULE = "Expressions/Context";
-    private static final TCon CONTEXT_TYPE = Types.con(CONTEXT_MODULE, "Context");
-    private static final Name CONTEXT_GET = Name.create(CONTEXT_MODULE, "contextGet");
+    private UpdateListener dependenciesListener;
+    
+    /**
+     * Only checks the commands for compilation errors but does not run them.
+     */
+    private boolean validateOnly; 
+    
+    public CommandSession(ModuleRepository moduleRepository) {
+        this(moduleRepository, SCLReporting.getCurrentReportingHandler());
+    }
 
     public CommandSession(ModuleRepository moduleRepository, SCLReportingHandler handler) {
         this.moduleRepository = moduleRepository;
@@ -108,10 +115,13 @@ public class CommandSession {
         
         runtimeEnvironment = null;
         try {
+            if(dependenciesListener != null)
+                dependenciesListener.stopListening();
             try {
                 runtimeEnvironment = moduleRepository.createRuntimeEnvironment(
                         environmentSpecification,
-                        getClass().getClassLoader());
+                        getClass().getClassLoader(),
+                        dependenciesListener);
             } catch(ImportFailureException e) {
                 THashSet<String> failedModules = new THashSet<String>();
                 for(ImportFailure failure : e.failures) {
@@ -119,7 +129,8 @@ public class CommandSession {
                     defaultHandler.printError(failure.toString());
                     if(failure.reason instanceof CompilationError[])
                         for(CompilationError error : (CompilationError[])failure.reason) {
-                            defaultHandler.printError("    " + error.description);
+                            if(error.severity != ErrorSeverity.WARNING)
+                                defaultHandler.printError("    " + error.description);
                         }
                 }
                 for(CommandSessionImportEntry entry : importEntries)
@@ -129,7 +140,7 @@ public class CommandSession {
                 try {
                     runtimeEnvironment = moduleRepository.createRuntimeEnvironment(
                             environmentSpecification,
-                            getClass().getClassLoader());
+                            getClass().getClassLoader()); // no listener here, because should listen also failed modules
                 } catch (ImportFailureException e1) {
                     for(ImportFailure failure : e1.failures)
                         defaultHandler.printError(failure.toString());
@@ -202,7 +213,7 @@ public class CommandSession {
         }, Types.functionE(Types.STRING, Types.PROC, Types.UNIT)));
         LOCAL_FUNCTIONS.put("reset", new LocalFunction(new FunctionImpl2<CommandSession, Tuple0, Tuple0>() {
             @Override
-            public Tuple0 apply(CommandSession commandSession, Tuple0 _) {
+            public Tuple0 apply(CommandSession commandSession, Tuple0 dummy) {
                 commandSession.removeTransientImports();
                 commandSession.removeVariables();
                 commandSession.moduleRepository.getSourceRepository().checkUpdates();
@@ -212,7 +223,7 @@ public class CommandSession {
         }, Types.functionE(Types.UNIT, Types.PROC, Types.UNIT)));
         LOCAL_FUNCTIONS.put("variables", new LocalFunction(new FunctionImpl2<CommandSession, Tuple0, List<String>>() {
             @Override
-            public List<String> apply(CommandSession commandSession, Tuple0 _) {
+            public List<String> apply(CommandSession commandSession, Tuple0 dummy) {
                 ArrayList<String> result = new ArrayList<String>(commandSession.variableTypes.keySet());
                 Collections.sort(result);
                 return result;
@@ -255,7 +266,7 @@ public class CommandSession {
         }, Types.functionE(Types.STRING, Types.PROC, Types.UNIT)));
         LOCAL_FUNCTIONS.put("stopPrintingToFile", new LocalFunction(new FunctionImpl2<CommandSession, Tuple0, Tuple0>() {
             @Override
-            public Tuple0 apply(final CommandSession commandSession, Tuple0 _) {
+            public Tuple0 apply(final CommandSession commandSession, Tuple0 dummy) {
                 if(commandSession.fileOutput != null) {
                     commandSession.fileOutput.close();
                     commandSession.fileOutput = null;
@@ -267,13 +278,13 @@ public class CommandSession {
 
     private LocalEnvironment createLocalEnvironment() {
         return new AbstractLocalEnvironment() {
-            Variable contextVariable = new Variable("context", CONTEXT_TYPE);
+            Variable contextVariable = new Variable("context", Names.Expressions_Context_Context);
             @Override
             public Expression resolve(Environment environment, String localName) {
                 Type type = variableTypes.get(localName);
                 if(type != null)
                     return new EApply(
-                            new EConstant(environment.getValue(CONTEXT_GET), type),
+                            new EConstant(environment.getValue(Names.Expressions_Context_contextGet), type),
                             new EVariable(contextVariable),
                             new ELiteral(new StringConstant(localName))
                             );
@@ -325,6 +336,7 @@ public class CommandSession {
         Function command = (Function)evaluator
             .localEnvironment(localEnvironment)
             .decorateExpression(true)
+            .validateOnly(validateOnly)
             .eval();
         return new CompiledCommand(command, evaluator.getType());
     }
@@ -366,7 +378,9 @@ public class CommandSession {
                 handler.printCommand(reader.extractString(expression.location));
                 command = compile(expression);
             } catch (SCLExpressionCompilationException e) {
-                CompilationError[] errors = ((SCLExpressionCompilationException)e).getErrors();
+                if(validateOnly)
+                    throw e;
+                CompilationError[] errors = e.getErrors();
                 for(CompilationError error : errors) {
                     if(error.location != Locations.NO_LOCATION)
                         handler.printError(reader.locationUnderlining(error.location));
@@ -376,11 +390,15 @@ public class CommandSession {
             }
             reader.forgetEverythingBefore(Locations.endOf(expression.location));
 
-            Object resultValue = command.command.apply(variableValues);
-            String resultString = toString(resultValue, command.type);
-            if(!resultString.isEmpty())
-                handler.print(resultString);
+            if(!validateOnly) {
+                Object resultValue = command.command.apply(variableValues);
+                String resultString = toString(resultValue, command.type);
+                if(!resultString.isEmpty())
+                    handler.print(resultString);
+            }
         } catch(Exception e) {
+            if(validateOnly)
+                throw e;
             if(!(e instanceof CancelExecution)) {
                 if(e instanceof InterruptedException)
                     handler.printError("Execution interrupted.");
@@ -416,10 +434,9 @@ public class CommandSession {
         void finishBlock() {
             if(currentBlock != null) {
                 checkInterrupted();
-                LinkedList<Statement> statements = currentBlock.getStatements();
                 currentBlock.location = Locations.combine(
-                        statements.getFirst().location,
-                        statements.getLast().location);
+                        currentBlock.getFirst().location,
+                        currentBlock.getLast().location);
                 execute(reader, currentBlock, handler);
                 currentBlock = null;
             }
@@ -468,6 +485,24 @@ public class CommandSession {
         }
     }
     
+    private CompilationError[] validate(Reader commandReader) {
+        CommandParser parser = new CommandParser(defaultHandler, new MemoReader(commandReader));
+        validateOnly = true;
+        try {
+            parser.parseCommands();
+            parser.finishBlock();
+            return CompilationError.EMPTY_ARRAY;
+        } catch(SCLExpressionCompilationException e) {
+            return e.getErrors();
+        } catch(SCLSyntaxErrorException e) {
+            return new CompilationError[] { new CompilationError(e.location, e.getMessage()) };
+        } catch(Exception e) {
+            return new CompilationError[] { new CompilationError(Locations.NO_LOCATION, e.getMessage()) };
+        } finally {
+            validateOnly = false;
+        }
+    }
+    
     public void execute(Reader commandReader, SCLReportingHandler handler) {
         if(handler == null)
             handler = defaultHandler;
@@ -483,7 +518,7 @@ public class CommandSession {
             if(e.location != Locations.NO_LOCATION)
                 handler.printError(parser.reader.locationUnderlining(e.location));
             handler.printError(e.getMessage());
-        } catch(Exception e) {
+        } catch (Exception | AssertionError e) {
             if(e instanceof InterruptedException)
                 handler.printError("Execution interrupted.");
             else
@@ -499,16 +534,6 @@ public class CommandSession {
         execute(new StringReader(command), handler);
     }
 
-    public CompilationError[] validate(String command) {
-        return CompilationError.EMPTY_ARRAY;
-        /*try {
-            compile(command);
-            return CompilationError.EMPTY_ARRAY;
-        } catch(SCLExpressionCompilationException e) {
-            return e.getErrors();
-        }*/
-    }
-
     private static final String THIS_CLASS_NAME = CommandSession.class.getName(); 
 
     public static void formatException(
@@ -580,7 +605,9 @@ public class CommandSession {
             b.append("\tat ");
             if("_SCL_Module".equals(fileName)
                     || "_SCL_TypeClassInstance".equals(fileName))
-                b.append(NameMangling.demangle(methodName))
+                b.append(className)
+                .append('.')
+                .append(NameMangling.demangle(methodName))
                 .append('(').append(element.getLineNumber()).append(')');
             else
                 b.append(element);
@@ -593,6 +620,11 @@ public class CommandSession {
         variableTypes.put(name, type);
     }
 
+    public void setVariable(String name, SafeDynamic typeAndValue) {
+        variableValues.put(name, typeAndValue.value);
+        variableTypes.put(name, typeAndValue.type_);
+    }
+
     public Object getVariableValue(String name) {
         return variableValues.get(name);
     }
@@ -601,6 +633,14 @@ public class CommandSession {
         return variableTypes.get(name);
     }
     
+    public SafeDynamic getVariableValueAndType(String name) {
+        Type type = variableTypes.get(name);
+        if(type == null)
+            return null;
+        Object value = variableValues.get(name);
+        return new SafeDynamic(type, value);
+    }
+    
     public void removeVariable(String name) {
        variableValues.remove(name);
        variableTypes.remove(name);
@@ -637,4 +677,21 @@ public class CommandSession {
             formatException(handler, e);
         }
     }
+
+    public static CompilationError[] validate(ModuleRepository moduleRepository,StringReader commandReader) {
+        CommandSession session = new CommandSession(moduleRepository, null);
+        return session.validate(commandReader);
+    }
+    
+    public static CompilationError[] validate(ModuleRepository moduleRepository,String command) {
+        return validate(moduleRepository, new StringReader(command));
+    }
+
+    public CompilationError[] validate(String command) {
+        return validate(new StringReader(command));
+    }
+
+    public void setDependenciesListener(UpdateListener dependenciesListener) {
+        this.dependenciesListener = dependenciesListener;
+    }
 }