(refs #7386) Minor SCL tools improvements
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / environment / Environments.java
1 package org.simantics.scl.compiler.environment;
2
3 import java.io.StringReader;
4 import java.util.ArrayList;
5 import java.util.List;
6 import java.util.function.Consumer;
7
8 import org.simantics.scl.compiler.common.names.Name;
9 import org.simantics.scl.compiler.compilation.CompilationContext;
10 import org.simantics.scl.compiler.elaboration.chr.CHRRuleset;
11 import org.simantics.scl.compiler.elaboration.contexts.TypeTranslationContext;
12 import org.simantics.scl.compiler.elaboration.modules.SCLValue;
13 import org.simantics.scl.compiler.elaboration.modules.TypeClass;
14 import org.simantics.scl.compiler.elaboration.modules.TypeDescriptor;
15 import org.simantics.scl.compiler.elaboration.relations.SCLEntityType;
16 import org.simantics.scl.compiler.elaboration.relations.SCLRelation;
17 import org.simantics.scl.compiler.elaboration.rules.MappingRelation;
18 import org.simantics.scl.compiler.elaboration.rules.TransformationRule;
19 import org.simantics.scl.compiler.environment.filter.AcceptAllNamespaceFilter;
20 import org.simantics.scl.compiler.internal.codegen.effects.EffectConstructor;
21 import org.simantics.scl.compiler.internal.parsing.exceptions.SCLSyntaxErrorException;
22 import org.simantics.scl.compiler.internal.parsing.parser.SCLParserImpl;
23 import org.simantics.scl.compiler.internal.parsing.types.TypeAst;
24 import org.simantics.scl.compiler.top.SCLExpressionCompilationException;
25 import org.simantics.scl.compiler.types.TCon;
26 import org.simantics.scl.compiler.types.Type;
27
28 import gnu.trove.procedure.TObjectProcedure;
29
30 public class Environments {
31     /**
32      * Get the SCLValue object representing an SCL value defined in a given environment.
33      * The name can be a local name or a fully scoped name with modules separated by periods. 
34      * @param environment  the environment
35      * @param localName  the name to be searched for
36      * @return  An SCLValue instance, or null if not found.
37      * @throws AmbiguousNameException  if the same name is found in multiple imported modules.
38      */
39     public static SCLValue getValue(Environment environment, String localName) throws AmbiguousNameException {
40         return getEnvironmentEntry(environment, localName, getValue);
41     }
42     
43     /**
44      * Get the SCLRelation object representing an SCL relation defined in a given environment.
45      * The name can be a local name or a fully scoped name with modules separated by periods. 
46      * @param environment  the environment
47      * @param localName  the name to be searched for
48      * @return  An SCLRelation instance, or null if not found.
49      * @throws AmbiguousNameException  if the same name is found in multiple imported modules.
50      */
51     public static SCLRelation getRelation(Environment environment, String localName) throws AmbiguousNameException {
52         return getEnvironmentEntry(environment, localName, getRelation);
53     }
54     
55     public static MappingRelation getMappingRelation(Environment environment, String localName) throws AmbiguousNameException {
56         return getEnvironmentEntry(environment, localName, getMappingRelation);
57     }
58     
59     public static TransformationRule getRule(Environment environment, String localName) throws AmbiguousNameException {
60         return getEnvironmentEntry(environment, localName, getRule);
61     }
62     
63     /**
64      * Get the SCLEntityType object representing an entity type defined in a given environment.
65      * The name can be a local name or a fully scoped name with modules separated by periods. 
66      * @param environment  the environment
67      * @param localName  the name to be searched for
68      * @return  An SCLEntityType instance, or null if not found.
69      * @throws AmbiguousNameException  if the same name is found in multiple imported modules.
70      */
71     public static SCLEntityType getEntityType(Environment environment, String localName) throws AmbiguousNameException {
72         return getEnvironmentEntry(environment, localName, getEntityType);
73     }
74     
75     /**
76      * Get the TypeConstructor object representing an type defined in a given environment.
77      * The name can be a local name or a fully scoped name with modules separated by periods. 
78      * @param environment  the environment
79      * @param localName  the name to be searched for
80      * @return  A TypeConstructor instance, or null if not found.
81      * @throws AmbiguousNameException  if the same name is found in multiple imported modules.
82      */
83     public static TypeDescriptor getTypeDescriptor(Environment environment, String localName) throws AmbiguousNameException {
84         return getEnvironmentEntry(environment, localName, getTypeDescriptor);
85     }
86     
87     /**
88      * Get the EffectConstructor object representing an effect defined in a given environment.
89      * The name can be a local name or a fully scoped name with modules separated by periods. 
90      * @param environment  the environment
91      * @param localName  the name to be searched for
92      * @return  An EffectConstructor instance, or null if not found.
93      * @throws AmbiguousNameException  if the same name is found in multiple imported modules.
94      */
95     public static EffectConstructor getEffectConstructor(Environment environment, String localName) throws AmbiguousNameException {
96         return getEnvironmentEntry(environment, localName, getEffectConstructor);
97     }
98     
99     /**
100      * Get the TypeClass object representing a type class defined in a given environment.
101      * The name can be a local name or a fully scoped name with modules separated by periods. 
102      * @param environment  the environment
103      * @param localName  the name to be searched for
104      * @return  A TypeClass instance, or null if not found.
105      * @throws AmbiguousNameException  if the same name is found in multiple imported modules.
106      */
107     public static TypeClass getTypeClass(Environment environment, String localName) throws AmbiguousNameException {
108         return getEnvironmentEntry(environment, localName, getTypeClass);
109     }
110
111     public static CHRRuleset getRuleset(Environment environment, String localName) throws AmbiguousNameException {
112         return getEnvironmentEntry(environment, localName, getRuleset);
113     }
114     
115     /**
116      * Get the Name object representing an SCL value defined in a given environment.
117      * The name can be a local name or a fully scoped name with modules separated by periods. 
118      * @param environment  the environment
119      * @param localName  the name to be searched for
120      * @return  A Name instance, or null if not found.
121      * @throws AmbiguousNameException  if the same name is used in multiple imported modules.
122      */
123     public static Name getValueName(Environment environment, String localName) throws AmbiguousNameException {
124         SCLValue value = getValue(environment, localName);
125         if(value == null)
126             return null;
127         else
128             return value.getName();
129     }
130     
131     /**
132      * Get the TCon object representing a type declared in a given environment.
133      * The name can be a local name or a fully scoped name with modules separated by periods. 
134      * @param environment  the environment
135      * @param localName  the name to be searched for
136      * @return  A TCon instance, or null if not found.
137      * @throws AmbiguousNameException  if the same name is used in multiple imported modules.
138      */
139     public static TCon getTypeDescriptorName(Environment environment, String localName) throws AmbiguousNameException {
140         TypeDescriptor typeDescriptor = getTypeDescriptor(environment, localName);
141         if(typeDescriptor == null)
142             return null;
143         else
144             return typeDescriptor.name;
145     }
146     
147     /**
148      * Get the TCon object representing an effect declared in a given environment.
149      * The name can be a local name or a fully scoped name with modules separated by periods. 
150      * @param environment  the environment
151      * @param localName  the name to be searched for
152      * @return  A TCon instance, or null if not found.
153      * @throws AmbiguousNameException  if the same name is used in multiple imported modules.
154      */
155     public static TCon getEffectConstructorName(Environment environment, String localName) throws AmbiguousNameException {
156         EffectConstructor effectConstructor = getEffectConstructor(environment, localName);
157         if(effectConstructor == null)
158             return null;
159         else
160             return effectConstructor.name;
161     }
162     
163     /**
164      * Get the TCon object representing a type class declared in a given environment.
165      * The name can be a local name or a fully scoped name with modules separated by periods. 
166      * @param environment  the environment
167      * @param localName  the name to be searched for
168      * @return  A TCon instance, or null if not found.
169      * @throws AmbiguousNameException  if the same name is used in multiple imported modules.
170      */
171     public static TCon getTypeClassName(Environment environment, String localName) throws AmbiguousNameException {
172         TypeClass typeClass = getTypeClass(environment, localName);
173         if(typeClass == null)
174             return null;
175         else
176             return typeClass.name;
177     }
178     
179     /**
180      * Parse a given SCL type expression into a Type defined in a given environment.
181      * @param environment  the environment
182      * @param typeText  an SCL language type expression
183      * @return  A Type instance
184      * @throws SCLExpressionCompilationException  if the expression compilation fails
185      */
186     public static Type getType(Environment environment, String typeText) throws SCLExpressionCompilationException {
187         SCLParserImpl parser = new SCLParserImpl(new StringReader(typeText));
188         CompilationContext compilationContext = new CompilationContext();
189         compilationContext.environment = environment;
190         try {
191             TypeAst typeAst = (TypeAst)parser.parseType();
192             TypeTranslationContext context = new TypeTranslationContext(compilationContext);
193             Type type = context.toType(typeAst);
194             if(compilationContext.errorLog.hasNoErrors())
195                 return type;
196         } catch(SCLSyntaxErrorException e) {
197             compilationContext.errorLog.log(e.location, e.getMessage());
198         } catch(Exception e) {
199             compilationContext.errorLog.log(e);
200         }
201         throw new SCLExpressionCompilationException(compilationContext.errorLog.getErrors());
202     }
203
204     /**
205      * Find a list of values in an environment that share a common prefix.
206      * The name can be a local name or a fully scoped name with modules separated by periods. 
207      * @param environment  An environment
208      * @param prefix  A name prefix
209      * @param values  A collection into which the found values are added
210      */
211     public static void findValuesForPrefix(Environment environment,
212             String prefix, TObjectProcedure<SCLValue> proc) {
213         findValuesForPrefix(environment.getLocalNamespace(), prefix, proc);
214     }
215     
216     public static List<SCLValue> findValuesForPrefix(Environment environment,
217             String prefix) {
218         final ArrayList<SCLValue> result = new ArrayList<SCLValue>();
219         findValuesForPrefix(environment, prefix,
220                 new TObjectProcedure<SCLValue>() {
221                     @Override
222                     public boolean execute(SCLValue value) {
223                         result.add(value);
224                         return true;
225                     }
226                 });
227         return result;
228     }
229     
230     /**
231      * Find a list of values in a namespace that share a common prefix.
232      * The name can be a local name or a fully scoped name with modules separated by periods. 
233      * @param namespace  An namespace
234      * @param prefix  A name prefix
235      * @param values  A collection into which the found values are added
236      */
237     public static void findValuesForPrefix(Namespace namespace,
238             String prefix, TObjectProcedure<SCLValue> proc) {
239         int p = prefix.indexOf('.');
240         if(p > 0) {
241             Namespace childNamespace = namespace.getNamespace(prefix.substring(0, p));
242             if(childNamespace != null)
243                 findValuesForPrefix(childNamespace, prefix.substring(p+1), proc);
244             else
245                 namespace.findValuesForPrefix(prefix, AcceptAllNamespaceFilter.INSTANCE, proc);
246         }
247         else
248             namespace.findValuesForPrefix(prefix, AcceptAllNamespaceFilter.INSTANCE, proc);
249     }
250     
251     public static List<TCon> findTypesForPrefix(Environment environment, String prefix) {
252         final List<TCon> results = new ArrayList<>();
253         findTypesForPrefix(environment.getLocalNamespace(), prefix, new Consumer<TCon>() {
254
255             @Override
256             public void accept(TCon tcon) {
257                 results.add(tcon);
258             }
259         });
260         return results;
261     }
262     
263     /**
264      * Find a list of values in a namespace that share a common prefix.
265      * The name can be a local name or a fully scoped name with modules separated by periods. 
266      * @param namespace  An namespace
267      * @param prefix  A name prefix
268      * @param values  A collection into which the found values are added
269      */
270     public static void findTypesForPrefix(Namespace namespace, String prefix, Consumer<TCon> consumer) {
271         int p = prefix.indexOf('.');
272         if(p > 0) {
273             Namespace childNamespace = namespace.getNamespace(prefix.substring(0, p));
274             if(childNamespace != null)
275                 findTypesForPrefix(childNamespace, prefix.substring(p+1), consumer);
276         }
277         else
278             namespace.findTypesForPrefix(prefix, AcceptAllNamespaceFilter.INSTANCE, consumer);
279     }
280     
281     /* Accessor objects for retrieving values from a namespace. */
282     
283     private static interface NamespaceValueAccessor<T> {
284         public T get(Namespace ns, String name) throws AmbiguousNameException;
285     }
286     
287     private static final NamespaceValueAccessor<SCLValue> getValue = new NamespaceValueAccessor<SCLValue>() {
288                 @Override
289                 public SCLValue get(Namespace ns, String name) throws AmbiguousNameException {
290                         return ns.getValue(name);
291                 }               
292         };
293     
294     private static final NamespaceValueAccessor<SCLRelation> getRelation = new NamespaceValueAccessor<SCLRelation>() {
295                 @Override
296                 public SCLRelation get(Namespace ns, String name) throws AmbiguousNameException {
297                         return ns.getRelation(name);
298                 }               
299         };
300     
301         private static final NamespaceValueAccessor<MappingRelation> getMappingRelation = new NamespaceValueAccessor<MappingRelation>() {
302         @Override
303         public MappingRelation get(Namespace ns, String name) throws AmbiguousNameException {
304             return ns.getMappingRelation(name);
305         }
306     };
307     
308     private static final NamespaceValueAccessor<TransformationRule> getRule = new NamespaceValueAccessor<TransformationRule>() {
309         @Override
310         public TransformationRule get(Namespace ns, String name) throws AmbiguousNameException {
311             return ns.getRule(name);
312         }
313     };
314     
315     private static final NamespaceValueAccessor<SCLEntityType> getEntityType = new NamespaceValueAccessor<SCLEntityType>() {
316                 @Override
317                 public SCLEntityType get(Namespace ns, String name) throws AmbiguousNameException {
318                         return ns.getEntityType(name);
319                 }               
320         };
321     
322     private static final NamespaceValueAccessor<TypeDescriptor> getTypeDescriptor = new NamespaceValueAccessor<TypeDescriptor>() {
323                 @Override
324                 public TypeDescriptor get(Namespace ns, String name) throws AmbiguousNameException {
325                         return ns.getTypeDescriptor(name);
326                 }               
327         };
328     
329     private static final NamespaceValueAccessor<EffectConstructor> getEffectConstructor = new NamespaceValueAccessor<EffectConstructor>() {
330                 @Override
331                 public EffectConstructor get(Namespace ns, String name) throws AmbiguousNameException {
332                         return ns.getEffectConstructor(name);
333                 }               
334         };
335     
336     private static final NamespaceValueAccessor<TypeClass> getTypeClass = new NamespaceValueAccessor<TypeClass>() {
337                 @Override
338                 public TypeClass get(Namespace ns, String name) throws AmbiguousNameException {
339                         return ns.getTypeClass(name);
340                 }               
341         };
342         
343     private static final NamespaceValueAccessor<CHRRuleset> getRuleset = new NamespaceValueAccessor<CHRRuleset>() {
344         @Override
345         public CHRRuleset get(Namespace ns, String name) throws AmbiguousNameException {
346             return ns.getRuleset(name);
347         }
348     };
349     
350         private static <T> T getEnvironmentEntry(Environment environment, String localName, NamespaceValueAccessor<T> accessor) throws AmbiguousNameException {
351         Namespace namespace = environment.getLocalNamespace();
352         int curPos = 0;
353         while(true) {
354             int pos = localName.indexOf('.', curPos);
355             if(pos < 0)
356                 return accessor.get(namespace, localName.substring(curPos));
357             Namespace newNamespace = namespace.getNamespace(localName.substring(curPos, pos));
358             if(newNamespace == null)
359                 return accessor.get(namespace, localName.substring(curPos));
360             namespace = newNamespace;
361             curPos = pos + 1;
362         }
363     }
364 }