3be214d2d6bd69f66aa4ae59347adeba2b5cb572
[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         }
245         else
246             namespace.findValuesForPrefix(prefix, AcceptAllNamespaceFilter.INSTANCE, proc);
247     }
248     
249     public static List<TCon> findTypesForPrefix(Environment environment, String prefix) {
250         final List<TCon> results = new ArrayList<>();
251         findTypesForPrefix(environment.getLocalNamespace(), prefix, new Consumer<TCon>() {
252
253             @Override
254             public void accept(TCon tcon) {
255                 results.add(tcon);
256             }
257         });
258         return results;
259     }
260     
261     /**
262      * Find a list of values in a namespace that share a common prefix.
263      * The name can be a local name or a fully scoped name with modules separated by periods. 
264      * @param namespace  An namespace
265      * @param prefix  A name prefix
266      * @param values  A collection into which the found values are added
267      */
268     public static void findTypesForPrefix(Namespace namespace, String prefix, Consumer<TCon> consumer) {
269         int p = prefix.indexOf('.');
270         if(p > 0) {
271             Namespace childNamespace = namespace.getNamespace(prefix.substring(0, p));
272             if(childNamespace != null)
273                 findTypesForPrefix(childNamespace, prefix.substring(p+1), consumer);
274         }
275         else
276             namespace.findTypesForPrefix(prefix, AcceptAllNamespaceFilter.INSTANCE, consumer);
277     }
278     
279     /* Accessor objects for retrieving values from a namespace. */
280     
281     private static interface NamespaceValueAccessor<T> {
282         public T get(Namespace ns, String name) throws AmbiguousNameException;
283     }
284     
285     private static final NamespaceValueAccessor<SCLValue> getValue = new NamespaceValueAccessor<SCLValue>() {
286                 @Override
287                 public SCLValue get(Namespace ns, String name) throws AmbiguousNameException {
288                         return ns.getValue(name);
289                 }               
290         };
291     
292     private static final NamespaceValueAccessor<SCLRelation> getRelation = new NamespaceValueAccessor<SCLRelation>() {
293                 @Override
294                 public SCLRelation get(Namespace ns, String name) throws AmbiguousNameException {
295                         return ns.getRelation(name);
296                 }               
297         };
298     
299         private static final NamespaceValueAccessor<MappingRelation> getMappingRelation = new NamespaceValueAccessor<MappingRelation>() {
300         @Override
301         public MappingRelation get(Namespace ns, String name) throws AmbiguousNameException {
302             return ns.getMappingRelation(name);
303         }
304     };
305     
306     private static final NamespaceValueAccessor<TransformationRule> getRule = new NamespaceValueAccessor<TransformationRule>() {
307         @Override
308         public TransformationRule get(Namespace ns, String name) throws AmbiguousNameException {
309             return ns.getRule(name);
310         }
311     };
312     
313     private static final NamespaceValueAccessor<SCLEntityType> getEntityType = new NamespaceValueAccessor<SCLEntityType>() {
314                 @Override
315                 public SCLEntityType get(Namespace ns, String name) throws AmbiguousNameException {
316                         return ns.getEntityType(name);
317                 }               
318         };
319     
320     private static final NamespaceValueAccessor<TypeDescriptor> getTypeDescriptor = new NamespaceValueAccessor<TypeDescriptor>() {
321                 @Override
322                 public TypeDescriptor get(Namespace ns, String name) throws AmbiguousNameException {
323                         return ns.getTypeDescriptor(name);
324                 }               
325         };
326     
327     private static final NamespaceValueAccessor<EffectConstructor> getEffectConstructor = new NamespaceValueAccessor<EffectConstructor>() {
328                 @Override
329                 public EffectConstructor get(Namespace ns, String name) throws AmbiguousNameException {
330                         return ns.getEffectConstructor(name);
331                 }               
332         };
333     
334     private static final NamespaceValueAccessor<TypeClass> getTypeClass = new NamespaceValueAccessor<TypeClass>() {
335                 @Override
336                 public TypeClass get(Namespace ns, String name) throws AmbiguousNameException {
337                         return ns.getTypeClass(name);
338                 }               
339         };
340         
341     private static final NamespaceValueAccessor<CHRRuleset> getRuleset = new NamespaceValueAccessor<CHRRuleset>() {
342         @Override
343         public CHRRuleset get(Namespace ns, String name) throws AmbiguousNameException {
344             return ns.getRuleset(name);
345         }
346     };
347     
348         private static <T> T getEnvironmentEntry(Environment environment, String localName, NamespaceValueAccessor<T> accessor) throws AmbiguousNameException {
349         Namespace namespace = environment.getLocalNamespace();
350         int curPos = 0;
351         while(true) {
352             int pos = localName.indexOf('.', curPos);
353             if(pos < 0)
354                 return accessor.get(namespace, localName.substring(curPos));
355             Namespace newNamespace = namespace.getNamespace(localName.substring(curPos, pos));
356             if(newNamespace == null)
357                 return accessor.get(namespace, localName.substring(curPos));
358             namespace = newNamespace;
359             curPos = pos + 1;
360         }
361     }
362 }