import org.simantics.db.layer0.function.All;
import org.simantics.db.layer0.request.PropertyInfo;
import org.simantics.db.layer0.request.PropertyInfoRequest;
+import org.simantics.db.layer0.scl.SCLDatabaseException;
import org.simantics.db.layer0.util.Layer0Utils;
import org.simantics.layer0.Layer0;
import org.simantics.utils.Development;
try {
- return (T)getValueAccessor(graph).getValue(graph, this, binding);
- } catch (PendingVariableException e) {
- throw e;
+ return (T) getValueAccessor(graph).getValue(graph, this, binding);
+ } catch (SCLDatabaseException e) { // these can be thrown when compiling e.g. derived properties
+ throw e;
+ } catch (MissingVariableValueException | PendingVariableException e) {
+ throw e;
} catch (Throwable t) {
throw new MissingVariableValueException(t);
}
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.simantics.db.services.adaption.reflection.ThisResource2;
import org.simantics.scl.reflection.OntologyVersions;
import org.simantics.utils.FileUtils;
+import org.simantics.utils.threads.ThreadUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
public class AdapterRegistry2 {
+ private static final Logger LOGGER = LoggerFactory.getLogger(AdapterRegistry2.class);
+
public static final String ADAPTERS_FILE = "adapters.xml";
public static final String ADAPTERS = "adapters";
public static final String CONSTRUCTOR = "constructor";
static private AdapterRegistry2 instance = new AdapterRegistry2();
- Collection<AdapterInstaller> installers = new ArrayList<AdapterInstaller>();
- Map<AdapterInstaller, String> installerSources = new HashMap<AdapterInstaller, String>();
+ ConcurrentHashMap<AdapterInstaller, String> installerSources = new ConcurrentHashMap<>();
Collection<Exception> exceptions = new ArrayList<Exception>();
public static AdapterRegistry2 getInstance() {
}
private void addInstaller(AdapterInstaller installer, String sourceDesc) {
- installers.add(installer);
installerSources.put(installer, sourceDesc);
}
- private void handleException(Exception e, String fileName) {
+ private static void handleException(Exception e, String fileName) {
System.err.println("At " + fileName);
e.printStackTrace();
}
s.syncRequest(new ReadRequest() {
@Override
public void run(ReadGraph g) {
- for(AdapterInstaller t : installers) {
+ for(AdapterInstaller t : installerSources.keySet()) {
try {
t.install(g, service);
} catch (Exception e) {
}
public void initialize(BundleContext context) {
-
+ LOGGER.info("Initializing");
try {
DocumentBuilderFactory factory =
}
// TODO Listen bundles (install/uninstall)
+ List<Future<?>> waitFor = new ArrayList<>();
if (exceptions.isEmpty())
for (final Bundle b : context.getBundles()) {
- URL file = b.getEntry(ADAPTERS_FILE);
- if (file != null) {
- String fileName = new Path(b.getLocation()).append(file.getPath()).toString();
- try {
- DocumentBuilder builder = factory.newDocumentBuilder();
- builder.setErrorHandler(new ErrorHandler() {
-
- @Override
- public void error(SAXParseException exception)
- throws SAXException {
- // TODO Put this error somewhere
- System.err.println("Parse error at "
- + b.getSymbolicName() + "/adapters.xml" +
- " line " + exception.getLineNumber() +
- " column " + exception.getColumnNumber() + ":");
- System.err.println(exception.getMessage());
- }
-
- @Override
- public void fatalError(SAXParseException exception)
- throws SAXException {
- error(exception);
- }
-
- @Override
- public void warning(SAXParseException exception)
- throws SAXException {
- error(exception);
- }
-
- });
-
- //System.out.println("bundle=" + b.getSymbolicName());
- String text = FileUtils.getContents(file);
- text = OntologyVersions.getInstance().currentVersion(text);
- StringReader reader = new StringReader( text );
- InputSource inputSource = new InputSource( reader );
- Document doc = builder.parse( inputSource );
- reader.close();
- handleAdaptersDocument(loader(b), doc, fileName);
- } catch (Exception e) {
- handleException(e, fileName);
-
+ Future<?> submit = ThreadUtils.getNonBlockingWorkExecutor().submit(() -> {
+ URL file = b.getEntry(ADAPTERS_FILE);
+ if (file != null) {
+ String fileName = new Path(b.getLocation()).append(file.getPath()).toString();
+ try {
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ builder.setErrorHandler(new ErrorHandler() {
+
+ @Override
+ public void error(SAXParseException exception) throws SAXException {
+ // TODO Put this error somewhere
+ System.err.println("Parse error at " + b.getSymbolicName() + "/adapters.xml"
+ + " line " + exception.getLineNumber() + " column "
+ + exception.getColumnNumber() + ":");
+ System.err.println(exception.getMessage());
+ }
+
+ @Override
+ public void fatalError(SAXParseException exception) throws SAXException {
+ error(exception);
+ }
+
+ @Override
+ public void warning(SAXParseException exception) throws SAXException {
+ error(exception);
+ }
+
+ });
+
+ // System.out.println("bundle=" + b.getSymbolicName());
+ String text = FileUtils.getContents(file);
+ text = OntologyVersions.getInstance().currentVersion(text);
+ StringReader reader = new StringReader(text);
+ InputSource inputSource = new InputSource(reader);
+ Document doc = builder.parse(inputSource);
+ reader.close();
+ handleAdaptersDocument(loader(b), doc, fileName);
+ } catch (Exception e) {
+ handleException(e, fileName);
+
+ }
}
- }
+ });
+ waitFor.add(submit);
+ }
+ // Let's wait in here
+ waitFor.forEach(f -> {
+ try {
+ f.get();
+ } catch (InterruptedException | ExecutionException e) {
+ LOGGER.error("Could not wait adapters to load", e);
}
+ });
+ LOGGER.info("Adapters installed");
} catch (Exception e) {
handleException(e, "(no file name available)");
}
DOC.Functions.sclValue : L0.ExternalValue
DOC.HandlerSCLValue <T L0.SCLValue
+ @L0.scl L0.SCLValueType.validator """\self -> compileSimupediaSCLHandlerValueExpression self""" "Variable -> <ReadGraph> String"
@L0.assert L0.ConvertsToValueWith
DOC.Functions.sclHandlerValue : L0.ExternalValue
stateVariable :: Variable -> <ReadGraph> Variable
compileDocumentSCLValueExpression :: Variable -> <ReadGraph> String
+ compileDocumentSCLHandlerValueExpression :: Variable -> <ReadGraph> String
primitiveProperties :: <Proc> DocumentProperties
}
}
+ public static String compileDocumentSCLHandlerValueExpression(ReadGraph graph, Variable context) {
+ try {
+ ServerSCLHandlerValueRequest.compile(graph, context);
+ return "";
+ } catch (Exception e) {
+ return resolveIssueMessage(e);
+ }
+ }
+
private static String resolveIssueMessage(Exception e) {
if (e instanceof ImportFailureException)
return "";
sender, e.time & 0xffffffff, MOUSE_ID, buttonStatus,
getStateMask(e),
getControlPosition(e), getScreenPosition(e),
- MouseWheelMovedEvent.WHEEL_UNIT_SCROLL,
- 0,
+ MouseWheelMovedEvent.WHEEL_UNIT_SCROLL,
+ MouseWheelMovedEvent.SCROLL_AMOUNT_ZERO,
e.count
));
}
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.simantics.modeling.userComponent.ComponentTypeCommands;
import org.simantics.scl.runtime.function.Function2;
import org.simantics.scl.runtime.function.Function4;
+import org.simantics.utils.threads.ThreadUtils;
import org.simantics.utils.ui.ErrorLogger;
public class ComponentTypeViewerData {
if (validator != null) {
org.eclipse.swt.widgets.Listener validationListener = new org.eclipse.swt.widgets.Listener() {
+
+ private ScheduledFuture<?> future;
+
@Override
public void handleEvent(Event e) {
final String newValue = text.getText();
- String error = validator.apply(Simantics.getSession(), componentType, propertyInfo.resource, newValue);
- if (error != null) {
- text.setBackground(text.getDisplay().getSystemColor(SWT.COLOR_RED));
- text.setToolTipText(error);
- return;
- } else {
- text.setBackground(null);
- text.setToolTipText(null);
- }
+ if (future != null && !future.isCancelled())
+ future.cancel(true);
+ future = ThreadUtils.getNonBlockingWorkExecutor().schedule(() -> {
+ String error = validator.apply(Simantics.getSession(), componentType, propertyInfo.resource, newValue);
+ if (!text.isDisposed()) {
+ text.getDisplay().asyncExec(() -> {
+ if (!text.isDisposed()) {
+ if (error != null) {
+ text.setBackground(text.getDisplay().getSystemColor(SWT.COLOR_RED));
+ text.setToolTipText(error);
+ return;
+ } else {
+ text.setBackground(null);
+ text.setToolTipText(null);
+ }
+ }
+
+ });
+ }
+ }, 500, TimeUnit.MILLISECONDS);
}
};
text.addListener(SWT.Modify, validationListener);
import org.simantics.db.RequestProcessor;
import org.simantics.db.Resource;
import org.simantics.db.WriteGraph;
-import org.simantics.db.common.request.PossibleIndexRoot;
+import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;
import org.simantics.db.common.request.UniqueRead;
import org.simantics.db.common.request.WriteRequest;
import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.request.PropertyInfo;
+import org.simantics.db.layer0.request.PropertyInfoRequest;
+import org.simantics.db.layer0.variable.StandardGraphChildVariable;
+import org.simantics.db.layer0.variable.StandardGraphPropertyVariable;
+import org.simantics.db.layer0.variable.Variable;
import org.simantics.layer0.Layer0;
+import org.simantics.modeling.scl.CompileProceduralSCLMonitorRequest;
+import org.simantics.modeling.scl.CompileSCLMonitorRequest;
import org.simantics.modeling.userComponent.ComponentTypeCommands;
+import org.simantics.scl.runtime.SCLContext;
+import org.simantics.scl.runtime.function.Function1;
import org.simantics.scl.runtime.function.Function4;
import org.simantics.structural.stubs.StructuralResource2;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class DerivedPropertiesSection implements ComponentTypeViewerSection {
private static final String[] COLUMN_NAMES = {
}
};
+ private static final Logger LOGGER = LoggerFactory.getLogger(DerivedPropertiesSection.class);
+
ComponentTypeViewerData data;
Table table;
TableColumn[] columns;
StructuralResource2 STR = StructuralResource2.getInstance(graph);
- Resource indexRoot = graph.syncRequest(new PossibleIndexRoot(componentType));
-
+ // TODO: this is a bit hackish but should get the job done in most parts and
+ // importantly indicates something for the user
+ PropertyInfo info = graph.syncRequest(new PropertyInfoRequest(relation), TransientCacheAsyncListener.<PropertyInfo>instance());
+ Variable parent = new StandardGraphChildVariable(null, null, componentType) {
+
+ public Resource getType(ReadGraph graph) throws DatabaseException {
+ return componentType;
+ };
+
+ public Variable getPossibleProperty(ReadGraph graph, String name) throws DatabaseException {
+ Variable prop = super.getPossibleProperty(graph, name);
+ if (prop != null) {
+ return prop;
+ } else {
+ return getChild(graph, name);
+ }
+ };
+ };
+
for(Resource literal : graph.getAssertedObjects(componentType, relation)) {
try {
- // TODO validation
+ Variable context = new StandardGraphPropertyVariable(parent, null, null, info, literal);
if(graph.isInstanceOf(componentType, STR.ProceduralComponentType)) {
- //Layer0 L0 = Layer0.getInstance(graph);
- //Resource environment = graph.getPossibleObject(literal, L0.SCLValue_environment);
- //ContextModule context = graph.sync(new TypeMonitorContextRequest(componentType));
- //String SCLMain = graph.syncRequest(new SCLMainModuleRequest(indexRoot));
- //CompilationContext cc = new CompilationContext(environment, context, SCLMain);
- //graph.syncRequest(new ActualCompileRequest(expression, cc), TransientCacheListener.<CompiledExpression>instance());
+ CompileProceduralSCLMonitorRequest.compileAndEvaluate(graph, context);
} else {
- //CompilationContext cc = new CompileSCLMonitorRequest(literal, componentType, indexRoot).getContext(graph);
- //graph.syncRequest(new ActualCompileRequest(expression, cc), TransientCacheListener.<CompiledExpression>instance());
- //graph.syncRequest(new CompileSCLMonitorRequest(graph, context));
+ compileAndEvaluate(graph, context, expression);
}
} catch (Exception e) {
if(index > 0) msg = msg.substring(index);
return msg;
}
-
}
-
return null;
-
}
});
} catch (DatabaseException e) {
- e.printStackTrace();
+ LOGGER.error("Could not validate ", e);
}
-
return null;
-
}
+ public static void compileAndEvaluate(ReadGraph graph, Variable context, String expression) throws DatabaseException {
+ SCLContext sclContext = SCLContext.getCurrent();
+ Object oldGraph = sclContext.get("graph");
+ try {
+ CompileSCLMonitorRequest compileSCLMonitorRequest = new CompileSCLMonitorRequest(graph, context) {
+ @Override
+ protected String getExpressionText(ReadGraph graph) throws DatabaseException {
+ return expression;
+ }
+ };
+ Function1<Variable,Object> exp = graph.syncRequest(compileSCLMonitorRequest);
+ sclContext.put("graph", graph);
+ //return exp.apply(context.getParent(graph));
+ } catch (DatabaseException e) {
+ throw (DatabaseException)e;
+ } catch (Throwable t) {
+ throw new DatabaseException(t);
+ } finally {
+ sclContext.put("graph", oldGraph);
+ }
+ }
+
@Override
public void update(ComponentTypePropertiesResult result) {
if (table.isDisposed())
return EventTypes.AnyMask;
}
- /**
- *
- */
- private MouseWheelMovedEvent lastMouseWheelMovedEvent;
-
private static final String DISABLE_DUPLICATE_REMOVAL = "org.simantics.scenegraph.g2d.events.disableDuplicateMouseWheelEvent";
private static final boolean IGNORE_DUPLICATE = !Boolean.parseBoolean(System.getProperty(DISABLE_DUPLICATE_REMOVAL));
private boolean ignoreDuplicateMouseWheelMovedEvent(Event e) {
if (IGNORE_DUPLICATE && e instanceof MouseWheelMovedEvent) {
- if (e.time > 0 && (lastMouseWheelMovedEvent != null && lastMouseWheelMovedEvent.time < 0)) {
+ MouseWheelMovedEvent event = (MouseWheelMovedEvent) e;
+ // if (e.time > 0 && (lastMouseWheelMovedEvent != null && lastMouseWheelMovedEvent.time < 0)) {
+ // apparently this is a better way to distinguish between SWT & AWT events
+ // SWT based event constructs the scrollAmount to = 0
+ // See org.simantics.g2d.event.adapter.SWTMouseEventAdapter.mouseScrolled(MouseEvent) L171
+ if (event.scrollAmount != MouseWheelMovedEvent.SCROLL_AMOUNT_ZERO) {
return true;
}
- lastMouseWheelMovedEvent = (MouseWheelMovedEvent) e;
}
return false;
}
private static final long serialVersionUID = -7896477913481842708L;
+ public static final int SCROLL_AMOUNT_ZERO = 0;
+
/**
* Constant representing scrolling by "units" (like scrolling with the
* arrow keys)
public static final Name Builtin_fail = Name.create(Types.BUILTIN, "fail");
public static final Name Builtin_runProc = Name.create(Types.BUILTIN, "runProc");
public static final Name Builtin_createCHRContext = Name.create(Types.BUILTIN, "createCHRContext");
+ public static final Name Builtin_Just = Name.create("Builtin", "Just");
+ public static final Name Builtin_Nothing = Name.create("Builtin", "Nothing");
public static final Name Data_XML_createElement = Name.create("Data/XML", "createElement");
public static final Type Data_XML_Element = Types.con("Data/XML", "Element");
public static final TCon Expressions_Context_Context = Types.con("Expressions/Context", "Context");
public static final Name Expressions_Context_contextGet = Name.create("Expressions/Context", "contextGet");
public static final Name JavaBuiltin_unsafeCoerce = Name.create("JavaBuiltin", "unsafeCoerce");
+ public static final TCon Json_Json = Types.con("Data/Json", "Json");
+ public static final Name Json_fromJson = Name.create("Data/Json", "fromJson");
+ public static final Name Json_toJson = Name.create("Data/Json", "toJson");
+ public static final Name Json_lookupJsonField = Name.create("Data/Json", "lookupJsonField");
+ public static final Name Json_JsonObject = Name.create("Data/Json", "JsonObject");
+ public static final Name Json_JsonField = Name.create("Data/Json", "JsonField");
public static final Name MList_add = Name.create("MList", "add");
public static final Name MList_create = Name.create("MList", "create");
public static final Name MList_freeze = Name.create("MList", "freeze");
public static final Name Prelude_bindE = Name.create("Prelude", "bindE");
public static final Name Prelude_build = Name.create("Prelude", "build");
public static final Name Prelude_concatMap = Name.create("Prelude", "concatMap");
+ public static final Name Prelude_dot = Name.create("Prelude", ".");
public static final Name Prelude_dollar = Name.create("Prelude", "$");
public static final Name Prelude_elem = Name.create("Prelude", "elem");
public static final Name Prelude_elemMaybe = Name.create("Prelude", "elemMaybe");
public static final Name Prelude_emptyList = Name.create("Prelude", "emptyList");
+ public static final Name Prelude_filterJust = Name.create("Prelude", "filterJust");
public static final Name Prelude_foldl = Name.create("Prelude", "foldl");
public static final Name Prelude_fromDouble = Name.create("Prelude", "fromDouble");
public static final Name Prelude_fromInteger = Name.create("Prelude", "fromInteger");
+ public static final Name Prelude_fromJust = Name.create("Prelude", "fromJust");
public static final Name Prelude_guardList = Name.create("Prelude", "guardList");
public static final Name Prelude_iterList = Name.create("Prelude", "iterList");
+ public static final Name Prelude_map = Name.create("Prelude", "map");
public static final Name Prelude_mapFirst = Name.create("Prelude", "mapFirst");
public static final Name Prelude_mapList = Name.create("Prelude", "mapList");
public static final Name Prelude_neg = Name.create("Prelude", "neg");
}
boolean trivialDataType = dataTypeAst.constructors.length == 1 &&
- dataTypeAst.constructors[0].parameters.length == 1;
+ dataTypeAst.constructors[0].parameters.length == 1 &&
+ !external;
if(className == null && !trivialDataType)
className = compilationContext.namingPolicy.getDataTypeClassName(dataTypeAst.name);
package org.simantics.scl.compiler.internal.deriving;
+import org.simantics.scl.compiler.common.names.Names;
import org.simantics.scl.compiler.types.TCon;
import org.simantics.scl.compiler.types.Types;
MAP.put(Types.IO, new IODeriver());
MAP.put(Types.ORD, new OrdDeriver());
MAP.put(Types.SHOW, new ShowDeriver());
+ MAP.put(Names.Json_Json, new JsonDeriver());
}
public static InstanceDeriver get(TCon typeClass) {
--- /dev/null
+package org.simantics.scl.compiler.internal.deriving;
+
+import java.util.ArrayList;
+
+import org.simantics.scl.compiler.common.datatypes.Constructor;
+import org.simantics.scl.compiler.common.names.Names;
+import org.simantics.scl.compiler.constants.StringConstant;
+import org.simantics.scl.compiler.elaboration.errors.NotPatternException;
+import org.simantics.scl.compiler.elaboration.expressions.EApply;
+import org.simantics.scl.compiler.elaboration.expressions.EConstant;
+import org.simantics.scl.compiler.elaboration.expressions.EListLiteral;
+import org.simantics.scl.compiler.elaboration.expressions.ELiteral;
+import org.simantics.scl.compiler.elaboration.expressions.ERecord;
+import org.simantics.scl.compiler.elaboration.expressions.EVar;
+import org.simantics.scl.compiler.elaboration.expressions.Expression;
+import org.simantics.scl.compiler.elaboration.expressions.records.FieldAssignment;
+import org.simantics.scl.compiler.elaboration.modules.SCLValue;
+import org.simantics.scl.compiler.elaboration.modules.TypeAlias;
+import org.simantics.scl.compiler.elaboration.modules.TypeConstructor;
+import org.simantics.scl.compiler.elaboration.modules.TypeDescriptor;
+import org.simantics.scl.compiler.environment.AmbiguousNameException;
+import org.simantics.scl.compiler.environment.Environment;
+import org.simantics.scl.compiler.environment.Environments;
+import org.simantics.scl.compiler.errors.ErrorLog;
+import org.simantics.scl.compiler.internal.parsing.declarations.DDerivingInstanceAst;
+import org.simantics.scl.compiler.internal.parsing.declarations.DInstanceAst;
+import org.simantics.scl.compiler.internal.parsing.declarations.DValueAst;
+import org.simantics.scl.compiler.internal.parsing.translation.ProcessedDInstanceAst;
+import org.simantics.scl.compiler.internal.parsing.translation.ValueRepository;
+import org.simantics.scl.compiler.internal.parsing.types.TVarAst;
+import org.simantics.scl.compiler.types.TApply;
+import org.simantics.scl.compiler.types.TCon;
+import org.simantics.scl.compiler.types.Type;
+import org.simantics.scl.compiler.types.Types;
+
+class JsonDeriver implements InstanceDeriver {
+
+ @Override
+ public void derive(
+ ErrorLog errorLog,
+ Environment environment,
+ ArrayList<ProcessedDInstanceAst> instancesAst,
+ DDerivingInstanceAst der) {
+ // Analyze
+ if(der.types.length != 1) {
+ errorLog.log(der.location, "Invalid number of parameters to " + der.name);
+ return;
+ }
+ TVarAst headType = DerivingUtils.getHeadType(der.types[0]);
+ if(headType == null) {
+ errorLog.log(der.types[0].location, "Cannot derive Json instance for the type " + headType + ".");
+ return;
+ }
+ TCon con;
+ try {
+ con = Environments.getTypeDescriptorName(environment, headType.name);
+ } catch (AmbiguousNameException e1) {
+ errorLog.log(headType.location, e1.getMessage());
+ return;
+ }
+ if(con == null) {
+ errorLog.log(headType.location, "Couldn't resolve " + headType.name);
+ return;
+ }
+ TypeDescriptor tdesc = environment.getTypeDescriptor(con);
+ if(tdesc == null) {
+ errorLog.log(headType.location, "Didn't find type constructor for " + headType.name);
+ return;
+ }
+ if(tdesc instanceof TypeAlias) {
+ errorLog.log(headType.location, "Cannot derive instance for a type alias.");
+ return;
+ }
+ TypeConstructor tcon = (TypeConstructor)tdesc;
+ if(tcon.isOpen) {
+ errorLog.log(headType.location, "Cannot derive instance for open data types.");
+ return;
+ }
+
+ if(tcon.constructors.length != 1) {
+ errorLog.log(headType.location, "Data must have exactly one constructor for deriving to work.");
+ return;
+ }
+ Constructor constructor = tcon.constructors[0];
+ if(constructor.recordFieldNames == null) {
+ errorLog.log(headType.location, "Data must have a record constructor for deriving to work.");
+ return;
+ }
+
+ DInstanceAst instanceAst = new DInstanceAst(der.location, der.context, der.name, der.types);
+ ValueRepository valueDefs = new ValueRepository();
+
+ SCLValue fromJson = environment.getValue(Names.Json_fromJson);
+ SCLValue toJson = environment.getValue(Names.Json_toJson);
+ SCLValue lookupJsonField = environment.getValue(Names.Json_lookupJsonField);
+ SCLValue JsonObject = environment.getValue(Names.Json_JsonObject);
+ SCLValue JsonField = environment.getValue(Names.Json_JsonField);
+
+ SCLValue Just = environment.getValue(Names.Builtin_Just);
+ SCLValue fromJust = environment.getValue(Names.Prelude_fromJust);
+ SCLValue map = environment.getValue(Names.Prelude_map);
+ SCLValue filterJust = environment.getValue(Names.Prelude_filterJust);
+ SCLValue dot = environment.getValue(Names.Prelude_dot);
+
+ // Collect all relevant information about the constructor
+ String constructorName = constructor.name.name;
+ int fieldCount = constructor.parameterTypes.length;
+ String[] fieldNames = constructor.recordFieldNames;
+ boolean[] isOptional = new boolean[fieldCount];
+ boolean hasAtLeastOneOptional = false;
+ for(int i=0;i<fieldCount;++i) {
+ Type type = constructor.parameterTypes[i];
+ hasAtLeastOneOptional |= isOptional[i] = type instanceof TApply
+ && ((TApply)type).function == Types.MAYBE;
+ }
+
+ // Generate toJson
+ {
+ /* toJson GeographicalLocation { latitude, longitude } = JsonObject [
+ * JsonField "latitude" (toJson latitude),
+ * JsonField "longitude" (toJson longitude)
+ * ]
+ * toJson GeographicalLocation { latitude, longitude } = JsonObject $ filterJust [
+ * Just (JsonField "latitude" (toJson latitude)),
+ * map (JsonField "longitude" . toJson) longitude
+ * ]
+ */
+ FieldAssignment[] fieldAssignments = new FieldAssignment[fieldCount];
+ for(int i=0;i<fieldCount;++i)
+ fieldAssignments[i] = new FieldAssignment(fieldNames[i], null);
+ Expression lhs = new EApply(
+ new EVar("toJson"),
+ new ERecord(new EVar(constructorName), fieldAssignments)
+ );
+ Expression componentsExpression;
+ if(hasAtLeastOneOptional) {
+ Expression[] components = new Expression[fieldCount];
+ for(int i=0;i<fieldCount;++i) {
+ if(isOptional[i])
+ components[i] = new EApply(new EConstant(map),
+ new EApply(new EConstant(dot),
+ new EApply(new EConstant(JsonField), new ELiteral(new StringConstant(fieldNames[i]))),
+ new EConstant(toJson)
+ ),
+ new EVar(fieldNames[i])
+ );
+ else
+ components[i] = new EApply(new EConstant(Just),
+ new EApply(new EConstant(JsonField),
+ new ELiteral(new StringConstant(fieldNames[i])),
+ new EApply(new EConstant(toJson), new EVar(fieldNames[i]))
+ ));
+ }
+ componentsExpression = new EApply(new EConstant(filterJust),
+ new EListLiteral(components));
+ }
+ else {
+ Expression[] components = new Expression[fieldCount];
+ for(int i=0;i<fieldCount;++i) {
+ components[i] = new EApply(new EConstant(JsonField),
+ new ELiteral(new StringConstant(fieldNames[i])),
+ new EApply(new EConstant(toJson), new EVar(fieldNames[i]))
+ );
+ }
+ componentsExpression = new EListLiteral(components);
+ }
+ Expression rhs = new EApply(new EConstant(JsonObject), componentsExpression);
+ try {
+ DValueAst valueAst = new DValueAst(lhs, rhs);
+ valueAst.setLocationDeep(der.location);
+ valueDefs.add(valueAst);
+ } catch (NotPatternException e) {
+ errorLog.log(e.getExpression().location, "Not a pattern (a).");
+ }
+ }
+
+ // Generate fromJson
+ {
+ /* fromJson object = GeographicalLocation {
+ * latitude = fromJson $ fromJust $ lookupJsonField "latitude" object,
+ * longitude = map fromJson $ lookupJsonField "longitude" object
+ * }
+ */
+ Expression lhs = new EApply(
+ new EVar("fromJson"),
+ new EVar("jsonObject")
+ );
+ FieldAssignment[] fieldAssignments = new FieldAssignment[fieldCount];
+ for(int i=0;i<fieldCount;++i) {
+ Expression fieldValue = new EApply(new EConstant(lookupJsonField),
+ new ELiteral(new StringConstant(fieldNames[i])),
+ new EVar("jsonObject")
+ );
+ if(isOptional[i]) {
+ fieldValue = new EApply(new EConstant(map), new EConstant(fromJson), fieldValue);
+ }
+ else {
+ fieldValue = new EApply(new EConstant(fromJust), fieldValue);
+ fieldValue = new EApply(new EConstant(fromJson), fieldValue);
+ }
+ fieldAssignments[i] = new FieldAssignment(fieldNames[i], fieldValue);
+ }
+ Expression rhs = new ERecord(new EVar(constructorName),
+ fieldAssignments
+ );
+ try {
+ DValueAst valueAst = new DValueAst(lhs, rhs);
+ valueAst.setLocationDeep(der.location);
+ valueDefs.add(valueAst);
+ } catch (NotPatternException e) {
+ errorLog.log(e.getExpression().location, "Not a pattern (b).");
+ }
+ }
+
+ instancesAst.add(new ProcessedDInstanceAst(instanceAst, valueDefs));
+ }
+
+}
+/*
+
+An example how to implement
+
+data GeographicalLocation = GeographicalLocation {
+ latitude :: Double,
+ longitude :: Double
+}
+
+instance Json GeographicalLocation where
+ toJson GeographicalLocation { latitude, longitude } = JsonObject [
+ JsonField "latitude" (toJson latitude),
+ JsonField "longitude" (toJson longitude)
+ ]
+ fromJson object = GeographicalLocation {
+ latitude = fromJson $ fromJust $ lookupJsonField "latitude" object,
+ longitude = fromJson $ fromJust $ lookupJsonField "longitude" object
+ }
+*/
+
import "StandardLibrary"
import "Data/Writer"
import "JavaBuiltin" as Java
readJson = getDoubleValue
toJson = JsonDouble
fromJson (JsonDouble value) = value
+ fromJson (JsonLong value) = Java.l2d value
instance Json Float where
writeJson = writeNumberFloat
| JsonObject [JsonField]
data JsonField = JsonField String Json
+lookupJsonField :: String -> Json -> Maybe Json
+lookupJsonField fieldName (JsonObject fields) = mapFirst selector fields
+ where
+ selector (JsonField name value) | name == fieldName = Just value
+ selector _ = Nothing
+
deriving instance Show Json
deriving instance Show JsonField
import org.eclipse.ui.texteditor.IUpdate;
import org.eclipse.ui.texteditor.SourceViewerDecorationSupport;
import org.eclipse.ui.texteditor.TextNavigationAction;
+import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
import org.simantics.scl.ui.editor.SCLSourceViewerConfigurationNew;
import org.simantics.scl.ui.editor.completion.SCLTextEditorEnvironment;
import org.simantics.scl.ui.editor2.iterator.DocumentCharacterIterator;
import org.simantics.scl.ui.editor2.iterator.JavaWordIterator;
+import org.simantics.scl.ui.outline.SCLModuleOutlinePage;
import com.ibm.icu.text.BreakIterator;
protected ResourceManager resourceManager;
private DefaultCharacterPairMatcher matcher;
+ private SCLModuleOutlinePage outline;
+
public SCLModuleEditor2() {
super();
resourceManager = new LocalResourceManager(JFaceResources.getResources());
SCLSourceViewerConfigurationNew sourceViewerConfiguration = new SCLSourceViewerConfigurationNew(resourceManager);
setDocumentProvider(new SCLModuleEditor2DocumentProvider(sourceViewerConfiguration));
setSourceViewerConfiguration(sourceViewerConfiguration);
+ outline = new SCLModuleOutlinePage(this);
}
@Override
public IDocument getDocument() {
return getSourceViewer().getDocument();
}
-
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <T> T getAdapter(Class<T> adapter) {
+ if (IContentOutlinePage.class.equals(adapter)) {
+ return (T) outline;
+ }
+ return super.getAdapter(adapter);
+ }
+
/**
* Text navigation action to navigate to the next sub-word.
*
package org.simantics.scl.ui.outline;
-import org.eclipse.jface.viewers.ILabelProvider;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider;
+import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider.IStyledLabelProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ITreeContentProvider;
-import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StyledString;
+import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.jface.viewers.TreeViewer;
-import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Tree;
-import org.eclipse.ui.part.Page;
-import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
+import org.eclipse.ui.views.contentoutline.ContentOutlinePage;
+import org.simantics.scl.compiler.elaboration.modules.SCLValue;
+import org.simantics.scl.compiler.environment.filter.AcceptAllNamespaceFilter;
+import org.simantics.scl.compiler.errors.Failable;
+import org.simantics.scl.compiler.errors.Locations;
+import org.simantics.scl.compiler.module.Module;
+import org.simantics.scl.compiler.module.repository.UpdateListener;
+import org.simantics.scl.compiler.source.ModuleSource;
+import org.simantics.scl.compiler.types.TCon;
+import org.simantics.scl.osgi.SCLOsgi;
+import org.simantics.scl.ui.Activator;
import org.simantics.scl.ui.editor2.SCLModuleEditor2;
+import org.simantics.scl.ui.editor2.SCLModuleEditorInput;
-public class SCLModuleOutlinePage extends Page implements IContentOutlinePage {
+public class SCLModuleOutlinePage extends ContentOutlinePage {
- private SCLOutlineViewer outlineViewer;
+ private TreeViewer outlineViewer;
private SCLModuleEditor2 moduleEditor;
-
+ private UpdateListener updateListener;
+ private LocalResourceManager resourceManager;
+ private Image publicImage;
+ private Image privateImage;
+ private Image typeImage;
+
public SCLModuleOutlinePage(SCLModuleEditor2 moduleEditor) {
this.moduleEditor = moduleEditor;
- }
-
- @Override
- public void addSelectionChangedListener(ISelectionChangedListener listener) {
- if (outlineViewer != null)
- outlineViewer.addSelectionChangedListener(listener);
- }
-
- @Override
- public ISelection getSelection() {
- if (outlineViewer != null)
- outlineViewer.getSelection();
- return StructuredSelection.EMPTY;
- }
-
- @Override
- public void removeSelectionChangedListener(ISelectionChangedListener listener) {
- if (outlineViewer != null)
- outlineViewer.removeSelectionChangedListener(listener);
- }
-
- @Override
- public void setSelection(ISelection selection) {
- if (outlineViewer != null)
- outlineViewer.setSelection(selection);
+ resourceManager = new LocalResourceManager(JFaceResources.getResources());
+ publicImage = resourceManager
+ .createImage(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/public_co.gif"));
+ privateImage = resourceManager
+ .createImage(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/private_co.gif"));
+ typeImage = resourceManager
+ .createImage(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/typedef_obj.gif"));
}
@Override
public void createControl(Composite parent) {
- Tree tree = new Tree(parent, SWT.MULTI);
- outlineViewer = new SCLOutlineViewer(tree);
-
+ super.createControl(parent);
+ outlineViewer = getTreeViewer();
+
SCLModuleOutlineProvider provider = new SCLModuleOutlineProvider();
+ DelegatingStyledCellLabelProvider labelProvider = new DelegatingStyledCellLabelProvider(provider);
outlineViewer.setContentProvider(provider);
- outlineViewer.setLabelProvider(provider);
-
- outlineViewer.setInput(moduleEditor.getEditorInput());
+ outlineViewer.setLabelProvider(labelProvider);
+ outlineViewer.addSelectionChangedListener(this);
+
+ SCLModuleEditorInput input = (SCLModuleEditorInput) moduleEditor.getEditorInput();
+ ModuleSource moduleSource = input.getAdapter(ModuleSource.class);
+ updateListener = new UpdateListener() {
+
+ @Override
+ public void notifyAboutUpdate() {
+ parent.getDisplay().asyncExec(() -> {
+ if (!outlineViewer.getControl().isDisposed()) {
+ outlineViewer.refresh();
+ }
+ });
+ }
+ };
+ Failable<Module> module = SCLOsgi.MODULE_REPOSITORY.getModule(moduleSource.getModuleName(), updateListener);
+ Module result = module.getResult();
+ outlineViewer.setInput(result);
}
@Override
- public Control getControl() {
- if (outlineViewer != null)
- outlineViewer.getControl();
- return null;
+ public void selectionChanged(SelectionChangedEvent event) {
+ super.selectionChanged(event);
+ ISelection selection = event.getSelection();
+ TreeSelection tselection = (TreeSelection) selection;
+ if (tselection.getFirstElement() instanceof SCLValue) {
+ SCLValue value = (SCLValue) tselection.getFirstElement();
+ long location = value.definitionLocation;
+ int begin = Locations.beginOf(location);
+ int end = Locations.endOf(location);
+ moduleEditor.selectAndReveal(begin, end - begin);
+ } else {
+// TCon type = (TCon) tselection.getFirstElement();
+// type.loction; // this is missing?
+ }
}
@Override
- public void setFocus() {
- if (outlineViewer != null)
- outlineViewer.getControl().setFocus();
+ public void dispose() {
+ resourceManager.dispose();
+ super.dispose();
}
- protected class SCLOutlineViewer extends TreeViewer {
-
- public SCLOutlineViewer(Tree tree) {
- super(tree);
- setAutoExpandLevel(ALL_LEVELS);
- setUseHashlookup(true);
- }
-
-
- }
-
- protected class SCLModuleOutlineProvider implements ITreeContentProvider, ILabelProvider {
+ protected class SCLModuleOutlineProvider implements ITreeContentProvider, IStyledLabelProvider {
@Override
public Object[] getElements(Object inputElement) {
- return null;
+ Module result = (Module) inputElement;
+ List<SCLValue> values = new ArrayList<>();
+ result.findValuesForPrefix("", AcceptAllNamespaceFilter.INSTANCE, value -> {
+ values.add(value);
+ });
+ values.sort(new Comparator<SCLValue>() {
+
+ @Override
+ public int compare(SCLValue o1, SCLValue o2) {
+ int isPrivate = Boolean.compare(o1.isPrivate(), o2.isPrivate());
+ if (isPrivate != 0)
+ return isPrivate;
+ else
+ return o1.getName().name.compareTo(o2.getName().name);
+ }
+ });
+ List<TCon> types = new ArrayList<>();
+ result.findTypesForPrefix("", AcceptAllNamespaceFilter.INSTANCE, type -> {
+ types.add(type);
+ });
+ types.sort(new Comparator<TCon>() {
+
+ @Override
+ public int compare(TCon o1, TCon o2) {
+ return o1.name.compareTo(o2.name);
+ }
+ });
+ List<Object> results = new ArrayList<>();
+ results.addAll(types);
+ results.addAll(values);
+ return results.toArray();
}
@Override
@Override
public void addListener(ILabelProviderListener listener) {
-
+
}
@Override
@Override
public void removeListener(ILabelProviderListener listener) {
-
+
}
@Override
public Image getImage(Object element) {
- return null;
+ if (element instanceof SCLValue) {
+ SCLValue value = (SCLValue) element;
+ if (value.isPrivate()) {
+ return privateImage;
+ } else {
+ return publicImage;
+ }
+ } else if (element instanceof TCon) {
+ return typeImage;
+ } else {
+ return null;
+ }
}
- @Override
- public String getText(Object element) {
- return null;
- }
-
@Override
public void dispose() {
ITreeContentProvider.super.dispose();
}
+ @Override
+ public StyledString getStyledText(Object element) {
+ if (element instanceof SCLValue) {
+ SCLValue value = (SCLValue) element;
+ StyledString ss = new StyledString(value.getName().name);
+ ss.append(" :: " + value.getType().toString(), StyledString.COUNTER_STYLER);
+ return ss;
+ } else {
+ TCon type = (TCon) element;
+ return new StyledString(type.name);
+ }
+ }
}
}
while((cur = cur.getCause()) != null) {
if(!(cur instanceof MissingVariableValueException)) {
handler.reportProblem(cur.getMessage());
- break;
}
}
} catch (Exception e) {
import org.simantics.db.Resource;
import org.simantics.db.common.procedure.adapter.TransientCacheListener;
import org.simantics.db.common.request.IndexRoot;
+import org.simantics.db.common.utils.NameUtils;
import org.simantics.db.exception.DatabaseException;
import org.simantics.db.layer0.variable.Variable;
import org.simantics.layer0.Layer0;
sclContext.put("graph", graph);
return exp.apply(context);
} catch (Throwable t) {
- throw new DatabaseException("Compiling structural value request for component=" + request.component + ", literal=" + request.literal + " and relation " + request.relation + " failed!", t);
+ String componentName = NameUtils.getSafeName(graph, request.component);
+ String literalName = NameUtils.getSafeName(graph, request.literal);
+ String relationName = NameUtils.getSafeName(graph, request.relation);
+ StringBuilder sb = new StringBuilder("Compiling structural value request for component ")
+ .append(componentName).append(" ").append(request.component).append(" , literal ")
+ .append(literalName).append(" ").append(request.literal).append(" and relation ")
+ .append(relationName).append(" ").append(request.relation).append(" failed!");
+ throw new DatabaseException(sb.toString(), t);
} finally {
sclContext.put("graph", oldGraph);
}