--- /dev/null
+package org.simantics.scl.compiler.environment;
+
+import gnu.trove.procedure.TObjectProcedure;
+
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+import org.simantics.scl.compiler.common.names.Name;
+import org.simantics.scl.compiler.elaboration.contexts.TypeTranslationContext;
+import org.simantics.scl.compiler.elaboration.modules.SCLValue;
+import org.simantics.scl.compiler.elaboration.modules.TypeAlias;
+import org.simantics.scl.compiler.elaboration.modules.TypeClass;
+import org.simantics.scl.compiler.elaboration.modules.TypeConstructor;
+import org.simantics.scl.compiler.elaboration.relations.SCLEntityType;
+import org.simantics.scl.compiler.elaboration.relations.SCLRelation;
+import org.simantics.scl.compiler.elaboration.rules.MappingRelation;
+import org.simantics.scl.compiler.elaboration.rules.TransformationRule;
+import org.simantics.scl.compiler.environment.filter.AcceptAllNamespaceFilter;
+import org.simantics.scl.compiler.errors.ErrorLog;
+import org.simantics.scl.compiler.internal.codegen.effects.EffectConstructor;
+import org.simantics.scl.compiler.internal.parsing.exceptions.SCLSyntaxErrorException;
+import org.simantics.scl.compiler.internal.parsing.parser.SCLParserImpl;
+import org.simantics.scl.compiler.internal.parsing.types.TypeAst;
+import org.simantics.scl.compiler.top.SCLExpressionCompilationException;
+import org.simantics.scl.compiler.types.TCon;
+import org.simantics.scl.compiler.types.Type;
+
+public class Environments {
+ /**
+ * Get the SCLValue object representing an SCL value defined in a given environment.
+ * The name can be a local name or a fully scoped name with modules separated by periods.
+ * @param environment the environment
+ * @param localName the name to be searched for
+ * @return An SCLValue instance, or null if not found.
+ * @throws AmbiguousNameException if the same name is found in multiple imported modules.
+ */
+ public static SCLValue getValue(Environment environment, String localName) throws AmbiguousNameException {
+ return getEnvironmentEntry(environment, localName, getValue);
+ }
+
+ /**
+ * Get the SCLRelation object representing an SCL relation defined in a given environment.
+ * The name can be a local name or a fully scoped name with modules separated by periods.
+ * @param environment the environment
+ * @param localName the name to be searched for
+ * @return An SCLRelation instance, or null if not found.
+ * @throws AmbiguousNameException if the same name is found in multiple imported modules.
+ */
+ public static SCLRelation getRelation(Environment environment, String localName) throws AmbiguousNameException {
+ return getEnvironmentEntry(environment, localName, getRelation);
+ }
+
+ public static MappingRelation getMappingRelation(Environment environment, String localName) throws AmbiguousNameException {
+ return getEnvironmentEntry(environment, localName, getMappingRelation);
+ }
+
+ public static TransformationRule getRule(Environment environment, String localName) throws AmbiguousNameException {
+ return getEnvironmentEntry(environment, localName, getRule);
+ }
+
+ /**
+ * Get the SCLEntityType object representing an entity type defined in a given environment.
+ * The name can be a local name or a fully scoped name with modules separated by periods.
+ * @param environment the environment
+ * @param localName the name to be searched for
+ * @return An SCLEntityType instance, or null if not found.
+ * @throws AmbiguousNameException if the same name is found in multiple imported modules.
+ */
+ public static SCLEntityType getEntityType(Environment environment, String localName) throws AmbiguousNameException {
+ return getEnvironmentEntry(environment, localName, getEntityType);
+ }
+
+ /**
+ * Get the TypeConstructor object representing an type defined in a given environment.
+ * The name can be a local name or a fully scoped name with modules separated by periods.
+ * @param environment the environment
+ * @param localName the name to be searched for
+ * @return A TypeConstructor instance, or null if not found.
+ * @throws AmbiguousNameException if the same name is found in multiple imported modules.
+ */
+ public static TypeConstructor getTypeConstructor(Environment environment, String localName) throws AmbiguousNameException {
+ return getEnvironmentEntry(environment, localName, getTypeConstructor);
+ }
+
+ /**
+ * Get the EffectConstructor object representing an effect defined in a given environment.
+ * The name can be a local name or a fully scoped name with modules separated by periods.
+ * @param environment the environment
+ * @param localName the name to be searched for
+ * @return An EffectConstructor instance, or null if not found.
+ * @throws AmbiguousNameException if the same name is found in multiple imported modules.
+ */
+ public static EffectConstructor getEffectConstructor(Environment environment, String localName) throws AmbiguousNameException {
+ return getEnvironmentEntry(environment, localName, getEffectConstructor);
+ }
+
+ /**
+ * Get the TypeClass object representing a type class defined in a given environment.
+ * The name can be a local name or a fully scoped name with modules separated by periods.
+ * @param environment the environment
+ * @param localName the name to be searched for
+ * @return A TypeClass instance, or null if not found.
+ * @throws AmbiguousNameException if the same name is found in multiple imported modules.
+ */
+ public static TypeClass getTypeClass(Environment environment, String localName) throws AmbiguousNameException {
+ return getEnvironmentEntry(environment, localName, getTypeClass);
+ }
+
+ /**
+ * Get the TypeAlias object representing a type alias defined in a given environment.
+ * The name can be a local name or a fully scoped name with modules separated by periods.
+ * @param environment the environment
+ * @param localName the name to be searched for
+ * @return A TypeAlias instance, or null if not found.
+ * @throws AmbiguousNameException if the same name is found in multiple imported modules.
+ */
+ public static TypeAlias getTypeAlias(Environment environment, String localName) throws AmbiguousNameException {
+ return getEnvironmentEntry(environment, localName, getTypeAlias);
+ }
+
+ /**
+ * Get the Name object representing an SCL value defined in a given environment.
+ * The name can be a local name or a fully scoped name with modules separated by periods.
+ * @param environment the environment
+ * @param localName the name to be searched for
+ * @return A Name instance, or null if not found.
+ * @throws AmbiguousNameException if the same name is used in multiple imported modules.
+ */
+ public static Name getValueName(Environment environment, String localName) throws AmbiguousNameException {
+ SCLValue value = getValue(environment, localName);
+ if(value == null)
+ return null;
+ else
+ return value.getName();
+ }
+
+ /**
+ * Get the TCon object representing a type declared in a given environment.
+ * The name can be a local name or a fully scoped name with modules separated by periods.
+ * @param environment the environment
+ * @param localName the name to be searched for
+ * @return A TCon instance, or null if not found.
+ * @throws AmbiguousNameException if the same name is used in multiple imported modules.
+ */
+ public static TCon getTypeConstructorName(Environment environment, String localName) throws AmbiguousNameException {
+ TypeConstructor typeConstructor = getTypeConstructor(environment, localName);
+ if(typeConstructor == null)
+ return null;
+ else
+ return typeConstructor.name;
+ }
+
+ /**
+ * Get the TCon object representing an effect declared in a given environment.
+ * The name can be a local name or a fully scoped name with modules separated by periods.
+ * @param environment the environment
+ * @param localName the name to be searched for
+ * @return A TCon instance, or null if not found.
+ * @throws AmbiguousNameException if the same name is used in multiple imported modules.
+ */
+ public static TCon getEffectConstructorName(Environment environment, String localName) throws AmbiguousNameException {
+ EffectConstructor effectConstructor = getEffectConstructor(environment, localName);
+ if(effectConstructor == null)
+ return null;
+ else
+ return effectConstructor.name;
+ }
+
+ /**
+ * Get the TCon object representing a type class declared in a given environment.
+ * The name can be a local name or a fully scoped name with modules separated by periods.
+ * @param environment the environment
+ * @param localName the name to be searched for
+ * @return A TCon instance, or null if not found.
+ * @throws AmbiguousNameException if the same name is used in multiple imported modules.
+ */
+ public static TCon getTypeClassName(Environment environment, String localName) throws AmbiguousNameException {
+ TypeClass typeClass = getTypeClass(environment, localName);
+ if(typeClass == null)
+ return null;
+ else
+ return typeClass.name;
+ }
+
+ /**
+ * Parse a given SCL type expression into a Type defined in a given environment.
+ * @param environment the environment
+ * @param typeText an SCL language type expression
+ * @return A Type instance
+ * @throws SCLExpressionCompilationException if the expression compilation fails
+ */
+ public static Type getType(Environment environment, String typeText) throws SCLExpressionCompilationException {
+ SCLParserImpl parser = new SCLParserImpl(new StringReader(typeText));
+ ErrorLog errorLog = new ErrorLog();
+ try {
+ TypeAst typeAst = (TypeAst)parser.parseType();
+ TypeTranslationContext context = new TypeTranslationContext(errorLog, environment);
+ Type type = context.toType(typeAst);
+ if(errorLog.isEmpty())
+ return type;
+ } catch(SCLSyntaxErrorException e) {
+ errorLog.log(e.location, e.getMessage());
+ } catch(Exception e) {
+ errorLog.log(e);
+ }
+ throw new SCLExpressionCompilationException(errorLog.getErrors());
+ }
+
+ /**
+ * Find a list of values in an environment that share a common prefix.
+ * The name can be a local name or a fully scoped name with modules separated by periods.
+ * @param environment An environment
+ * @param prefix A name prefix
+ * @param values A collection into which the found values are added
+ */
+ public static void findValuesForPrefix(Environment environment,
+ String prefix, TObjectProcedure<SCLValue> proc) {
+ findValuesForPrefix(environment.getLocalNamespace(), prefix, proc);
+ }
+
+ public static List<SCLValue> findValuesForPrefix(Environment environment,
+ String prefix) {
+ final ArrayList<SCLValue> result = new ArrayList<SCLValue>();
+ findValuesForPrefix(environment, prefix,
+ new TObjectProcedure<SCLValue>() {
+ @Override
+ public boolean execute(SCLValue value) {
+ result.add(value);
+ return true;
+ }
+ });
+ return result;
+ }
+
+ /**
+ * Find a list of values in a namespace that share a common prefix.
+ * The name can be a local name or a fully scoped name with modules separated by periods.
+ * @param namespace An namespace
+ * @param prefix A name prefix
+ * @param values A collection into which the found values are added
+ */
+ public static void findValuesForPrefix(Namespace namespace,
+ String prefix, TObjectProcedure<SCLValue> proc) {
+ int p = prefix.indexOf('.');
+ if(p > 0) {
+ Namespace childNamespace = namespace.getNamespace(prefix.substring(0, p));
+ if(childNamespace != null)
+ findValuesForPrefix(childNamespace, prefix.substring(p+1), proc);
+ }
+ else
+ namespace.findValuesForPrefix(prefix, AcceptAllNamespaceFilter.INSTANCE, proc);
+ }
+
+ public static List<TCon> findTypesForPrefix(Environment environment, String prefix) {
+ final List<TCon> results = new ArrayList<>();
+ findTypesForPrefix(environment.getLocalNamespace(), prefix, new Consumer<TCon>() {
+
+ @Override
+ public void accept(TCon tcon) {
+ results.add(tcon);
+ }
+ });
+ return results;
+ }
+
+ /**
+ * Find a list of values in a namespace that share a common prefix.
+ * The name can be a local name or a fully scoped name with modules separated by periods.
+ * @param namespace An namespace
+ * @param prefix A name prefix
+ * @param values A collection into which the found values are added
+ */
+ public static void findTypesForPrefix(Namespace namespace, String prefix, Consumer<TCon> consumer) {
+ int p = prefix.indexOf('.');
+ if(p > 0) {
+ Namespace childNamespace = namespace.getNamespace(prefix.substring(0, p));
+ if(childNamespace != null)
+ findTypesForPrefix(childNamespace, prefix.substring(p+1), consumer);
+ }
+ else
+ namespace.findTypesForPrefix(prefix, AcceptAllNamespaceFilter.INSTANCE, consumer);
+ }
+
+ /* Accessor objects for retrieving values from a namespace. */
+
+ private static interface NamespaceValueAccessor<T> {
+ public T get(Namespace ns, String name) throws AmbiguousNameException;
+ }
+
+ private static final NamespaceValueAccessor<SCLValue> getValue = new NamespaceValueAccessor<SCLValue>() {
+ @Override
+ public SCLValue get(Namespace ns, String name) throws AmbiguousNameException {
+ return ns.getValue(name);
+ }
+ };
+
+ private static final NamespaceValueAccessor<SCLRelation> getRelation = new NamespaceValueAccessor<SCLRelation>() {
+ @Override
+ public SCLRelation get(Namespace ns, String name) throws AmbiguousNameException {
+ return ns.getRelation(name);
+ }
+ };
+
+ private static final NamespaceValueAccessor<MappingRelation> getMappingRelation = new NamespaceValueAccessor<MappingRelation>() {
+ @Override
+ public MappingRelation get(Namespace ns, String name) throws AmbiguousNameException {
+ return ns.getMappingRelation(name);
+ }
+ };
+
+ private static final NamespaceValueAccessor<TransformationRule> getRule = new NamespaceValueAccessor<TransformationRule>() {
+ @Override
+ public TransformationRule get(Namespace ns, String name) throws AmbiguousNameException {
+ return ns.getRule(name);
+ }
+ };
+
+ private static final NamespaceValueAccessor<SCLEntityType> getEntityType = new NamespaceValueAccessor<SCLEntityType>() {
+ @Override
+ public SCLEntityType get(Namespace ns, String name) throws AmbiguousNameException {
+ return ns.getEntityType(name);
+ }
+ };
+
+ private static final NamespaceValueAccessor<TypeConstructor> getTypeConstructor = new NamespaceValueAccessor<TypeConstructor>() {
+ @Override
+ public TypeConstructor get(Namespace ns, String name) throws AmbiguousNameException {
+ return ns.getTypeConstructor(name);
+ }
+ };
+
+ private static final NamespaceValueAccessor<EffectConstructor> getEffectConstructor = new NamespaceValueAccessor<EffectConstructor>() {
+ @Override
+ public EffectConstructor get(Namespace ns, String name) throws AmbiguousNameException {
+ return ns.getEffectConstructor(name);
+ }
+ };
+
+ private static final NamespaceValueAccessor<TypeClass> getTypeClass = new NamespaceValueAccessor<TypeClass>() {
+ @Override
+ public TypeClass get(Namespace ns, String name) throws AmbiguousNameException {
+ return ns.getTypeClass(name);
+ }
+ };
+
+ private static final NamespaceValueAccessor<TypeAlias> getTypeAlias = new NamespaceValueAccessor<TypeAlias>() {
+ @Override
+ public TypeAlias get(Namespace ns, String name) throws AmbiguousNameException {
+ return ns.getTypeAlias(name);
+ }
+ };
+
+ private static <T> T getEnvironmentEntry(Environment environment, String localName, NamespaceValueAccessor<T> accessor) throws AmbiguousNameException {
+ Namespace namespace = environment.getLocalNamespace();
+ int curPos = 0;
+ while(true) {
+ int pos = localName.indexOf('.', curPos);
+ if(pos < 0)
+ return accessor.get(namespace, localName.substring(curPos));
+ namespace = namespace.getNamespace(localName.substring(curPos, pos));
+ if(namespace == null)
+ return null;
+ curPos = pos + 1;
+ }
+ }
+}