]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/Elaboration.java
(refs #7250) CHR rules modularization (first working version)
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / compilation / Elaboration.java
1 package org.simantics.scl.compiler.compilation;
2
3 import java.util.ArrayList;
4 import java.util.Iterator;
5 import java.util.List;
6
7 import org.cojen.classfile.TypeDesc;
8 import org.simantics.scl.compiler.common.datatypes.Constructor;
9 import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
10 import org.simantics.scl.compiler.common.names.Name;
11 import org.simantics.scl.compiler.constants.Constant;
12 import org.simantics.scl.compiler.constants.JavaTypeInstanceConstructor;
13 import org.simantics.scl.compiler.constants.SCLConstructor;
14 import org.simantics.scl.compiler.constants.StringConstant;
15 import org.simantics.scl.compiler.constants.generic.CallJava;
16 import org.simantics.scl.compiler.constants.generic.ClassRef;
17 import org.simantics.scl.compiler.constants.generic.ConvertToListFilter;
18 import org.simantics.scl.compiler.constants.generic.MethodRef;
19 import org.simantics.scl.compiler.constants.generic.MethodRef.FieldRef;
20 import org.simantics.scl.compiler.constants.generic.OutputFilter;
21 import org.simantics.scl.compiler.constants.generic.ParameterStackItem;
22 import org.simantics.scl.compiler.constants.generic.Pop2OutputFilter;
23 import org.simantics.scl.compiler.constants.generic.PopOutputFilter;
24 import org.simantics.scl.compiler.constants.generic.StackItem;
25 import org.simantics.scl.compiler.constants.generic.ThreadLocalStackItem;
26 import org.simantics.scl.compiler.constants.singletons.SafeCoerce;
27 import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
28 import org.simantics.scl.compiler.elaboration.contexts.TypeTranslationContext;
29 import org.simantics.scl.compiler.elaboration.errors.NotPatternException;
30 import org.simantics.scl.compiler.elaboration.expressions.EApply;
31 import org.simantics.scl.compiler.elaboration.expressions.EGetConstraint;
32 import org.simantics.scl.compiler.elaboration.expressions.EIntegerLiteral;
33 import org.simantics.scl.compiler.elaboration.expressions.EListLiteral;
34 import org.simantics.scl.compiler.elaboration.expressions.ELiteral;
35 import org.simantics.scl.compiler.elaboration.expressions.EPreCHRRulesetConstructor;
36 import org.simantics.scl.compiler.elaboration.expressions.EVar;
37 import org.simantics.scl.compiler.elaboration.expressions.Expression;
38 import org.simantics.scl.compiler.elaboration.expressions.Variable;
39 import org.simantics.scl.compiler.elaboration.expressions.annotations.AnnotationUtils;
40 import org.simantics.scl.compiler.elaboration.fundeps.Fundep;
41 import org.simantics.scl.compiler.elaboration.java.JavaMethodDeclaration;
42 import org.simantics.scl.compiler.elaboration.macros.StandardMacroRule;
43 import org.simantics.scl.compiler.elaboration.modules.DeprecatedProperty;
44 import org.simantics.scl.compiler.elaboration.modules.InlineProperty;
45 import org.simantics.scl.compiler.elaboration.modules.MethodImplementation;
46 import org.simantics.scl.compiler.elaboration.modules.PrivateProperty;
47 import org.simantics.scl.compiler.elaboration.modules.SCLValue;
48 import org.simantics.scl.compiler.elaboration.modules.TypeAlias;
49 import org.simantics.scl.compiler.elaboration.modules.TypeClass;
50 import org.simantics.scl.compiler.elaboration.modules.TypeClassInstance;
51 import org.simantics.scl.compiler.elaboration.modules.TypeClassMethod;
52 import org.simantics.scl.compiler.elaboration.modules.TypeDescriptor;
53 import org.simantics.scl.compiler.elaboration.query.Query;
54 import org.simantics.scl.compiler.elaboration.query.pre.QPreGuard;
55 import org.simantics.scl.compiler.elaboration.relations.ConcreteRelation;
56 import org.simantics.scl.compiler.elaboration.rules.MappingRelation;
57 import org.simantics.scl.compiler.elaboration.rules.SectionName;
58 import org.simantics.scl.compiler.elaboration.rules.TransformationRule;
59 import org.simantics.scl.compiler.environment.AmbiguousNameException;
60 import org.simantics.scl.compiler.environment.Environment;
61 import org.simantics.scl.compiler.environment.EnvironmentFactory;
62 import org.simantics.scl.compiler.environment.Environments;
63 import org.simantics.scl.compiler.errors.ErrorLog;
64 import org.simantics.scl.compiler.errors.Locations;
65 import org.simantics.scl.compiler.internal.codegen.effects.EffectConstructor;
66 import org.simantics.scl.compiler.internal.codegen.effects.ThreadLocalVariable;
67 import org.simantics.scl.compiler.internal.codegen.types.JavaReferenceValidator;
68 import org.simantics.scl.compiler.internal.codegen.types.JavaReferenceValidatorFactory;
69 import org.simantics.scl.compiler.internal.codegen.types.JavaTypeTranslator;
70 import org.simantics.scl.compiler.internal.codegen.types.StandardTypeConstructor;
71 import org.simantics.scl.compiler.internal.codegen.utils.Constants;
72 import org.simantics.scl.compiler.internal.codegen.utils.JavaNamingPolicy;
73 import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilderBase;
74 import org.simantics.scl.compiler.internal.deriving.InstanceDeriver;
75 import org.simantics.scl.compiler.internal.deriving.InstanceDerivers;
76 import org.simantics.scl.compiler.internal.elaboration.profiling.BranchPointInjector;
77 import org.simantics.scl.compiler.internal.elaboration.utils.StronglyConnectedComponents;
78 import org.simantics.scl.compiler.internal.header.ModuleHeader;
79 import org.simantics.scl.compiler.internal.parsing.declarations.ConstructorAst;
80 import org.simantics.scl.compiler.internal.parsing.declarations.DAnnotationAst;
81 import org.simantics.scl.compiler.internal.parsing.declarations.DClassAst;
82 import org.simantics.scl.compiler.internal.parsing.declarations.DDataAst;
83 import org.simantics.scl.compiler.internal.parsing.declarations.DDerivingInstanceAst;
84 import org.simantics.scl.compiler.internal.parsing.declarations.DEffectAst;
85 import org.simantics.scl.compiler.internal.parsing.declarations.DFixityAst;
86 import org.simantics.scl.compiler.internal.parsing.declarations.DInstanceAst;
87 import org.simantics.scl.compiler.internal.parsing.declarations.DMappingRelationAst;
88 import org.simantics.scl.compiler.internal.parsing.declarations.DRelationAst;
89 import org.simantics.scl.compiler.internal.parsing.declarations.DRuleAst;
90 import org.simantics.scl.compiler.internal.parsing.declarations.DRulesetAst;
91 import org.simantics.scl.compiler.internal.parsing.declarations.DTypeAst;
92 import org.simantics.scl.compiler.internal.parsing.declarations.DValueAst;
93 import org.simantics.scl.compiler.internal.parsing.declarations.DValueTypeAst;
94 import org.simantics.scl.compiler.internal.parsing.exceptions.SCLSyntaxErrorException;
95 import org.simantics.scl.compiler.internal.parsing.translation.ProcessedDClassAst;
96 import org.simantics.scl.compiler.internal.parsing.translation.ProcessedDInstanceAst;
97 import org.simantics.scl.compiler.internal.parsing.translation.RelationRepository;
98 import org.simantics.scl.compiler.internal.parsing.translation.ValueRepository;
99 import org.simantics.scl.compiler.internal.parsing.types.TypeAst;
100 import org.simantics.scl.compiler.module.ConcreteModule;
101 import org.simantics.scl.compiler.module.ImportDeclaration;
102 import org.simantics.scl.compiler.module.InvalidModulePathException;
103 import org.simantics.scl.compiler.module.ModuleUtils;
104 import org.simantics.scl.compiler.module.repository.ImportFailure;
105 import org.simantics.scl.compiler.module.repository.ImportFailureException;
106 import org.simantics.scl.compiler.types.TCon;
107 import org.simantics.scl.compiler.types.TForAll;
108 import org.simantics.scl.compiler.types.TFun;
109 import org.simantics.scl.compiler.types.TPred;
110 import org.simantics.scl.compiler.types.TVar;
111 import org.simantics.scl.compiler.types.Type;
112 import org.simantics.scl.compiler.types.Types;
113 import org.simantics.scl.compiler.types.kinds.Kind;
114 import org.simantics.scl.compiler.types.kinds.Kinds;
115 import org.simantics.scl.compiler.types.util.MultiFunction;
116 import org.simantics.scl.runtime.profiling.BranchPoint;
117
118 import gnu.trove.list.array.TIntArrayList;
119 import gnu.trove.map.hash.THashMap;
120 import gnu.trove.map.hash.TObjectIntHashMap;
121 import gnu.trove.procedure.TObjectObjectProcedure;
122 import gnu.trove.set.hash.THashSet;
123 import gnu.trove.set.hash.TIntHashSet;
124
125 public class Elaboration {
126     // inputs
127     private final CompilationContext compilationContext;
128     private final ErrorLog errorLog;
129     private final String moduleName;
130     private final ModuleHeader moduleHeader;
131     private final ArrayList<ImportDeclaration> importsAst;
132     private final JavaReferenceValidatorFactory jrvFactory;
133     final JavaReferenceValidator<Object, Object, Object, Object> javaReferenceValidator;
134     private final ValueRepository valueDefinitionsAst;
135     private final RelationRepository relationDefinitionsAst;
136
137     // creates
138     ConcreteModule module;
139     Environment importedEnvironment;
140     ArrayList<SupplementedValueType> supplementedTypeAnnotations = new ArrayList<SupplementedValueType>();
141     
142     JavaTypeTranslator javaTypeTranslator;
143     ArrayList<StandardTypeConstructor> dataTypes = new ArrayList<StandardTypeConstructor>();
144     THashMap<String, ClassRef> classRefs = new THashMap<String, ClassRef>();
145     THashMap<String, BranchPoint[]> branchPoints; 
146     
147     public Elaboration(CompilationContext compilationContext, CompilationTimer timer, EnvironmentFactory localEnvironmentFactory,
148             String moduleName, ModuleHeader moduleHeader, ArrayList<ImportDeclaration> importsAst,
149             JavaReferenceValidatorFactory jrvFactory,
150             ValueRepository valueDefinitionsAst,
151             RelationRepository relationDefinitionsAst) {
152         this.compilationContext = compilationContext;
153         this.errorLog = compilationContext.errorLog;
154         this.moduleName = moduleName;
155         this.moduleHeader = moduleHeader;
156         importsAst = processRelativeImports(importsAst);
157         this.importsAst = importsAst;
158         this.jrvFactory = jrvFactory;
159         this.javaReferenceValidator = moduleHeader == null || moduleHeader.classLoader == null
160                 ? jrvFactory.getDefaultJavaReferenceValidator()
161                 : jrvFactory.getJavaReferenceValidator(moduleHeader.classLoader);
162         if(javaReferenceValidator == null)
163             errorLog.log(moduleHeader.classLoaderLocation, "Didn't find the specified class loader.");
164         this.valueDefinitionsAst = valueDefinitionsAst;
165         this.relationDefinitionsAst = relationDefinitionsAst;
166
167         module = new ConcreteModule(moduleName);
168         compilationContext.module = module;
169         if(moduleHeader != null && moduleHeader.defaultLocalName != null)
170                 module.setDefaultLocalName(moduleHeader.defaultLocalName);
171         try {
172             if(timer != null)
173                 timer.suspendTimer();
174             importedEnvironment = localEnvironmentFactory.createEnvironment(
175                     importsAst.toArray(new ImportDeclaration[importsAst.size()]));
176             if(timer != null)
177                 timer.continueTimer();
178             compilationContext.environment = new EnvironmentOfModule(importedEnvironment, module);
179         } catch (ImportFailureException e) {
180             for(ImportFailure failure : e.failures)
181                 errorLog.log(failure.location, failure.toString());
182             return;
183         }
184         for(ImportDeclaration importAst : importsAst)
185             this.module.addDependency(new ImportDeclaration(
186                     importAst.moduleName,
187                     importAst.reexport ? importAst.localName : null,
188                     false,
189                     importAst.spec));
190         localEnvironmentFactory.addBuiltinDependencies(module);
191         compilationContext.namingPolicy = new JavaNamingPolicy(moduleName);
192     }
193     
194     private ArrayList<ImportDeclaration> processRelativeImports(ArrayList<ImportDeclaration> relativeImports) {
195         ArrayList<ImportDeclaration> absoluteImports = new ArrayList<ImportDeclaration>(relativeImports.size());
196         for(ImportDeclaration relativeImport : relativeImports) {
197             if(relativeImport.moduleName.startsWith(".")) {
198                                 try {
199                                         String absoluteModuleName = ModuleUtils.resolveAbsolutePath(moduleName, relativeImport.moduleName);
200                     ImportDeclaration absoluteImport = new ImportDeclaration(
201                             absoluteModuleName, relativeImport.localName,
202                             relativeImport.reexport, relativeImport.spec);
203                     absoluteImport.location = relativeImport.location;
204                     absoluteImports.add(absoluteImport);
205                                 } catch (InvalidModulePathException e) {
206                                         errorLog.log(relativeImport.location, e.getMessage());
207                                 }
208             }
209             else
210                 absoluteImports.add(relativeImport);
211         }
212         return absoluteImports;
213     }
214
215     public void addTypesToEnvironment(
216             ArrayList<DDataAst> dataTypesAst,
217             ArrayList<DTypeAst> typeAliasesAst,
218             ArrayList<DEffectAst> effectsAst,
219             ArrayList<DRulesetAst> rulesetsAst) {
220         for(DDataAst dataType : dataTypesAst) {
221             dataType.parameterKinds = new Kind[dataType.parameters.length];
222             Kind constructorKind = Kinds.STAR;
223             for(int i=dataType.parameters.length-1;i>=0;--i) {
224                 Kind kind = Kinds.metaVar();
225                 dataType.parameterKinds[i] = kind;
226                 constructorKind = Kinds.arrow(kind, constructorKind);
227             }
228             
229             StandardTypeConstructor typeConstructor = new StandardTypeConstructor(
230                     Types.con(moduleName, dataType.name), constructorKind);
231
232             NameExistenceChecks.checkIfTypeExists(errorLog,
233                     dataType.location, importedEnvironment, dataType.name);
234             addTypeDescriptor(dataType.location, dataType.name, typeConstructor);
235             dataType.typeConstructor = typeConstructor;
236         }
237         
238         for(DTypeAst typeAlias : typeAliasesAst) {
239             TypeAlias alias = new TypeAlias(Types.con(moduleName, typeAlias.name), typeAlias.parameters.length);
240             NameExistenceChecks.checkIfTypeExists(errorLog,
241                     typeAlias.location, importedEnvironment, typeAlias.name);
242             addTypeDescriptor(typeAlias.location, typeAlias.name, alias);
243         }
244         
245         for(DEffectAst effect : effectsAst) {
246             EffectConstructor effectConstructor = new EffectConstructor(Types.con(moduleName, effect.name));
247             effectConstructor.addThreadLocalVariable(
248                     new ThreadLocalVariable(
249                             effect.variableName,
250                             TypeDesc.forClass(effect.threadLocalType)
251                             ));
252             if(module.addEffectConstructor(effect.name, effectConstructor))
253                 errorLog.log(effect.location, "Effect "+effect.name+" has already been defined in this module.");
254         }
255         for(DRulesetAst ruleset : rulesetsAst) {
256             ruleset.type = Types.con(moduleName, ruleset.name);
257             ruleset.className = compilationContext.namingPolicy.getDataTypeClassName(ruleset.name);
258             StandardTypeConstructor typeConstructor = new StandardTypeConstructor(ruleset.type, Kinds.STAR,
259                     TypeDesc.forClass(ruleset.className), ruleset.documentation == null ? null : ruleset.documentation.documentation);
260             typeConstructor.external = true;
261             addTypeDescriptor(ruleset.location, ruleset.name, typeConstructor);
262         }
263         javaTypeTranslator = new JavaTypeTranslator(compilationContext.environment);
264         compilationContext.javaTypeTranslator = javaTypeTranslator;
265     }
266         
267     private void addTypeDescriptor(long location, String name, TypeDescriptor typeDescriptor) {
268         if(module.addTypeDescriptor(name, typeDescriptor))
269             errorLog.log(location, "Type "+name+" has already been defined in this module.");
270     }
271     
272     private static final int[] EMPTY_INT_ARRAY = new int[0];
273     
274     public void processTypeAliases(ArrayList<DTypeAst> typeAliasesAst) {
275         TObjectIntHashMap<String> typeAliasMap = new TObjectIntHashMap<String>();
276         for(int i=0;i<typeAliasesAst.size();++i)
277             typeAliasMap.put(typeAliasesAst.get(i).name, i); 
278         TIntHashSet tempIntSet = new TIntHashSet();
279         ArrayList<DTypeAst> orderedTypeAliases = new ArrayList<DTypeAst>(typeAliasesAst.size()); 
280         //for(int i=0;i<typeAliasesAst.size();++i)
281         //    System.out.println(i + "# " + typeAliasesAst.get(i).name);
282         new StronglyConnectedComponents(typeAliasesAst.size()) {
283             @Override
284             protected int[] findDependencies(int u) {
285                 typeAliasesAst.get(u).type.collectReferences(typeAliasMap, tempIntSet);
286                 if(tempIntSet.isEmpty())
287                     return EMPTY_INT_ARRAY;
288                 if(tempIntSet.contains(u)) {
289                     errorLog.log(typeAliasesAst.get(u).location, "Type alias has a self reference.");
290                     tempIntSet.remove(u);
291                 }
292                 int[] result = tempIntSet.toArray();
293                 tempIntSet.clear();
294                 //System.out.println(u + " -> " + Arrays.toString(result));
295                 return result; 
296             }
297             @Override
298             protected void reportComponent(int[] component) {
299                 //System.out.println("component: " + Arrays.toString(component));
300                 if(component.length > 1) {
301                     StringBuilder b = new StringBuilder();
302                     b.append("Recursively defined type alias (");
303                     long minLocation = typeAliasesAst.get(component[0]).location;
304                     boolean first = true;
305                     for(int u : component) {
306                         DTypeAst typeAlias = typeAliasesAst.get(u);
307                         if(first)
308                             first = false;
309                         else
310                             b.append(", ");
311                         b.append(typeAlias.name);
312                         if(Locations.beginOf(typeAlias.location) < Locations.beginOf(minLocation))
313                             minLocation = typeAlias.location;
314                     }
315                     b.append(").");
316                     errorLog.log(minLocation, b.toString());
317                 }
318                 else
319                     orderedTypeAliases.add(typeAliasesAst.get(component[0]));
320             }
321         }.findComponents();
322         
323         if(errorLog.hasNoErrors()) {
324             for(DTypeAst typeAlias : orderedTypeAliases) {
325                 TypeAlias alias = (TypeAlias)module.getTypeDescriptor(typeAlias.name);
326                 TypeTranslationContext context = createTypeTranslationContext();
327                 for(int i=0;i<typeAlias.parameters.length;++i)
328                     context.pushTypeVar(typeAlias.parameters[i]);
329                 alias.body = typeAlias.type.toType(context, Kinds.metaVar());
330                 for(int i=0;i<typeAlias.parameters.length;++i)
331                     alias.parameters[i] = context.popTypeVar(typeAlias.parameters[i], null);
332             }
333         }
334     }
335     
336     public void processDataTypes(ArrayList<DDataAst> dataTypesAst) {
337         ArrayList<Runnable> fieldAccessorGenerators = new ArrayList<Runnable>(); 
338         for(DDataAst dataTypeAst : dataTypesAst) {
339             TypeTranslationContext context = createTypeTranslationContext();
340             TVar[] typeParameters = new TVar[dataTypeAst.parameters.length];
341             for(int i=0;i<dataTypeAst.parameters.length;++i)
342                 typeParameters[i] = context.addTypeVar(dataTypeAst.parameters[i]);
343             Constructor[] constructors = new Constructor[dataTypeAst.constructors.length];
344             String className = null;
345             boolean external = false;
346             for(DAnnotationAst annotation : dataTypeAst.getAnnotations()) {
347                 if(annotation.id.text.equals("@JavaType")) {
348                     if(annotation.parameters.length != 1 || 
349                             !(annotation.parameters[0] instanceof ELiteral) ||
350                             !(((ELiteral)annotation.parameters[0]).getValue() instanceof StringConstant))
351                         errorLog.log(annotation.location, "Invalid parameters. Expected @JavaType \"className\".");
352                     else {
353                         className = ((StringConstant)((ELiteral)annotation.parameters[0]).getValue()).getValue().replace('.', '/');
354                         external = true;                        
355                         break;
356                     }
357                 }
358             }
359             
360             boolean trivialDataType = dataTypeAst.constructors.length == 1 &&
361                     dataTypeAst.constructors[0].parameters.length == 1;
362             if(className == null && !trivialDataType)
363                 className = compilationContext.namingPolicy.getDataTypeClassName(dataTypeAst.name);
364             
365             StandardTypeConstructor dataType = dataTypeAst.typeConstructor;
366             
367             dataType.setType(Types.con(moduleName, dataTypeAst.name), typeParameters);
368             dataType.setConstructors(constructors);
369             if(!trivialDataType)
370                 dataType.setTypeDesc(TypeDesc.forClass(className));            
371             if(!external || dataTypeAst.constructors.length > 0) {
372                 dataType.isOpen = false;
373             }
374             dataType.external = external;
375             dataTypes.add(dataType);
376             for(int j=0;j<constructors.length;++j) {
377                 ConstructorAst constructor = dataTypeAst.constructors[j];
378                 String name = constructor.name;
379                 Type[] parameterTypes = new Type[constructor.parameters.length];
380                 for(int i=constructor.parameters.length-1;i>=0;--i)
381                     parameterTypes[i] = context.toType(constructor.parameters[i]);
382                 String javaName = constructors.length == 1 ? className 
383                         : compilationContext.namingPolicy.getConstructorClassName(name);
384                 String[] fieldNames = null;
385                 for(DAnnotationAst annotation : constructor.annotations)
386                     if(annotation.id.text.equals("@JavaType")) {
387                         try {
388                             javaName = ((StringConstant)((ELiteral)annotation.parameters[0])
389                                     .getValue()).getValue();
390                         } catch(Exception e) {
391                             errorLog.log(annotation.parameters[0].location, "Invalid annotation parameter.");
392                         }
393                     }
394                     else if(annotation.id.text.equals("@FieldNames")) {
395                         try {
396                             EListLiteral literal = (EListLiteral)annotation.parameters[0];
397                             fieldNames = new String[literal.getComponents().length];
398                             for(int i=0;i<fieldNames.length;++i) {
399                                 Expression component = literal.getComponents()[i];
400                                 if(component instanceof EVar)
401                                     fieldNames[i] = ((EVar)component).name;
402                                 else if(component instanceof ELiteral)
403                                     fieldNames[i] = ((StringConstant)((ELiteral)component).getValue()).getValue();
404                             }
405                         } catch(Exception e) {
406                             errorLog.log(annotation.parameters[0].location, "Invalid annotation parameter.");
407                             fieldNames = null;
408                         }
409                     }   
410                 
411                 constructors[j] = new Constructor(constructor.location, dataType,
412                         Name.create(moduleName, name), 
413                         parameterTypes, javaName);
414                 constructors[j].fieldNames = fieldNames;
415                 constructors[j].recordFieldNames = constructor.fieldNames;
416             }
417             if(constructors.length == 1) {
418                 Constructor constructor = constructors[0];
419                 if(constructor.recordFieldNames != null) {
420                     fieldAccessorGenerators.add(new Runnable() {
421                         @Override
422                         public void run() {
423                             Type in = Types.apply(dataType.name, dataType.parameters);
424                             for(int i=0;i<constructor.recordFieldNames.length;++i) {
425                                 Type out = constructor.parameterTypes[i];
426                                 Constant accessor;
427                                 if(trivialDataType)
428                                     accessor = new SafeCoerce(dataType.parameters, in, out);
429                                 else
430                                     accessor = new CallJava(dataType.parameters, Types.NO_EFFECTS, out,
431                                             new Type[] {in}, new StackItem[] {new ParameterStackItem(0, in)},
432                                             new FieldRef(constructor.javaName, constructor.fieldNames != null ? constructor.fieldNames[i] : "c" + i,
433                                                     javaTypeTranslator.toTypeDesc(out)),
434                                             null);
435                                 module.addFieldAccessor(constructor.recordFieldNames[i], accessor);
436                             }
437                         }
438                     });
439                 }
440             }
441         }
442         
443         for(Runnable fieldAccessorGenerator : fieldAccessorGenerators)
444             fieldAccessorGenerator.run();
445     }
446     
447     public void processTypeClasses(ArrayList<ProcessedDClassAst> typeClassesAst) {
448         for(ProcessedDClassAst pClassAst : typeClassesAst) {
449             DClassAst classAst = pClassAst.orig;
450             
451             if(module.getTypeClass(classAst.name) != null) {
452                 errorLog.log(classAst.location, "Class "+classAst.name+" has already been defined in this module.");
453                 continue;
454             }
455             
456             TypeTranslationContext context = createTypeTranslationContext();            
457             
458             TPred[] classContext = new TPred[classAst.context.length];
459             for(int i=0;i<classContext.length;++i)
460                 classContext[i] = context.toTFuncApply(classAst.context[i]);
461             
462             TVar[] parameters = new TVar[classAst.parameters.length];
463             
464             if(classAst.name.equals("Functor") || classAst.name.equals("Monad")) {
465                 // FIXME hack
466                 parameters[0] = context.resolveTypeVariable(pClassAst.orig.location, classAst.parameters[0], Kinds.STAR_TO_STAR);
467             }
468             else {
469                 for(int i=0;i<parameters.length;++i)
470                     parameters[i] = context.resolveTypeVariable(pClassAst.orig.location, classAst.parameters[i], Kinds.metaVar());
471             }
472                         
473             TCon con = Types.con(moduleName, classAst.name);
474             TypeClass typeClass = new TypeClass(classAst.location, 
475                     classContext, 
476                     con, 
477                     compilationContext.namingPolicy.getTypeClassInterfaceName(con),
478                     parameters,
479                     Fundep.mapFundeps(classAst.parameters, classAst.fundeps));
480             
481             THashMap<String, TypeClassMethod> methods = typeClass.methods;
482             for(DValueTypeAst methodDecl : pClassAst.typeDeclarations) {
483                 try {
484                     Type type;
485                     try {
486                         type = context.toType(methodDecl.type);
487                     } catch(SCLSyntaxErrorException e) {
488                         errorLog.log(e.location, e.getMessage());
489                         continue;
490                     }
491                     for(EVar name : methodDecl.names) {
492                         typeClass.methodNames.add(name.name);
493                         methods.put(name.name,
494                                 new TypeClassMethod(typeClass, name.name, 
495                                         compilationContext.namingPolicy.getMethodName(name.name),
496                                         type, Types.getArity(type),
497                                         name.location)
498                                 );
499                     }
500                 } catch(RuntimeException e) {
501                     errorLog.setExceptionPosition(methodDecl.location);
502                     throw e;
503                 }
504             }
505             
506             for(String methodName : pClassAst.defaultImplementations.getValueNames()) {
507                 String fullName = "_" + classAst.name + "_default_" + methodName;                
508                 ArrayList<DValueAst> defs = pClassAst.defaultImplementations.getDefinition(methodName);
509                 
510                 TypeClassMethod method = typeClass.methods.get(methodName);
511                 if(method == null) {
512                     errorLog.log(defs.get(0).location, "Method " + methodName + " is not defined in this class.");
513                     continue;
514                 }
515                 method.setDefaultImplementation(Name.create(moduleName, fullName));
516                 
517                 valueDefinitionsAst.addDefinitions(fullName, defs);
518                 /*valueDefinitionsAst.addAnnotation(fullName, new DAnnotationAst(new EVar("@private"), 
519                         Collections.<Expression>emptyList()));*/
520                 supplementedTypeAnnotations.add(new SupplementedValueType(defs.get(0).location, fullName, method.getType()));                
521             }
522             
523             module.addTypeClass(classAst.name, typeClass);
524         }
525     }
526
527     private TypeTranslationContext createTypeTranslationContext() {
528         return new TypeTranslationContext(compilationContext);
529     }
530     
531     public void processDerivingInstances(ArrayList<DDerivingInstanceAst> derivingInstancesAst,
532             ArrayList<ProcessedDInstanceAst> instancesAst) {
533         for(DDerivingInstanceAst derivingInstance : derivingInstancesAst) {
534             String name = derivingInstance.name.name;
535             TCon con;
536             try {
537                 con = Environments.getTypeClassName(compilationContext.environment, name);
538             } catch (AmbiguousNameException e) {
539                 errorLog.log(derivingInstance.name.location, e.getMessage());
540                 continue;
541             }
542             if(con == null) {
543                 errorLog.log(derivingInstance.name.location, "Couldn't resolve class " + name + ".");
544                 continue;
545             }
546             InstanceDeriver deriver = InstanceDerivers.get(con);
547             if(deriver == null)
548                 errorLog.log(derivingInstance.location, "Doesn't know how to derive " + name + ".");
549             else
550                 deriver.derive(errorLog, compilationContext.environment, instancesAst, derivingInstance);
551         }
552     }
553     
554     public void processInstances(ArrayList<ProcessedDInstanceAst> instancesAst) {
555         THashSet<TPred> instanceClashCheckSet = new THashSet<TPred>(); 
556         for(ProcessedDInstanceAst pInstanceAst : instancesAst) {
557             DInstanceAst instanceAst = pInstanceAst.orig;
558             try {
559                 TypeTranslationContext context = createTypeTranslationContext();
560                 
561                 String name = instanceAst.name.name;
562                 TCon typeClassCon;
563                 try {
564                     typeClassCon = Environments.getTypeClassName(compilationContext.environment, name);
565                 } catch (AmbiguousNameException e) {
566                     errorLog.log(instanceAst.name.location, e.getMessage());
567                     continue;
568                 }
569                 if(typeClassCon == null) {
570                     errorLog.log(instanceAst.name.location, "Couldn't resolve class " + name + ".");
571                     continue;
572                 }
573                 TypeClass typeClass = compilationContext.environment.getTypeClass(typeClassCon);
574                 pInstanceAst.typeClass = typeClass;
575                 
576                 if(instanceAst.types.length != typeClass.parameters.length) {
577                     errorLog.log(instanceAst.location, "Wrong number of parameters to type class " + typeClassCon.name + ".");
578                     continue;
579                 }
580                 Type[] parameters = new Type[instanceAst.types.length];
581                 for(int i=0;i<parameters.length;++i)
582                     parameters[i] = context.toType(instanceAst.types[i], typeClass.parameters[i].getKind() /* FIXME */);
583                 TPred instance = Types.pred(typeClassCon, parameters);
584                 
585                 if(!instanceClashCheckSet.add(instance)) {
586                     errorLog.log(instanceAst.location, "Duplicate definition of the instance " + instance + ".");
587                     continue;
588                 }
589                 
590                 TPred[] instanceContext = new TPred[instanceAst.context.length];
591                 for(int i=0;i<instanceContext.length;++i)
592                     instanceContext[i] = context.toTFuncApply(instanceAst.context[i]);
593                 
594                 String javaName = compilationContext.namingPolicy.getInstanceClassName(instance);
595                 String instancePrefix = instance.toName() + "$";
596     
597                 ValueRepository valueDefs = pInstanceAst.valueDefs;
598     
599                 THashMap<String, MethodImplementation> methodImplementations =
600                         new THashMap<String, MethodImplementation>();
601                 for(String valueName : valueDefs.getValueNames()) {
602                     String fullName = instancePrefix + valueName;
603                     long loc = valueDefs.getDefinition(valueName).get(0).location;
604                     valueDefinitionsAst.addFrom(valueDefs, valueName, fullName);
605                     /*valueDefinitionsAst.addAnnotation(fullName, new DAnnotationAst(new EVar("@private"), 
606                             Collections.<Expression>emptyList()));*/
607                     TypeClassMethod method = typeClass.methods.get(valueName);
608                     if(method == null) {
609                         errorLog.log(loc, "Method " + valueName + " is not defined in the type class " + typeClass.name.name + ".");
610                         continue;
611                     }
612                     Type type = method.getBaseType().replace(typeClass.parameters, parameters);
613                     for(int i=instanceContext.length-1;i>=0;--i)
614                         type = Types.constrained(instanceContext[i], type);
615                     //System.out.println(valueName + " :: " + type);
616                     supplementedTypeAnnotations.add(
617                             new SupplementedValueType(loc, fullName, type));
618                     methodImplementations.put(valueName,
619                             new MethodImplementation(Name.create(moduleName, fullName), false));
620                 }
621                 
622                 // Are all necessary methods defined
623                 for(String methodName : typeClass.methods.keySet())
624                     if(!methodImplementations.containsKey(methodName)) {
625                         Name defaultImplementation = typeClass.methods.get(methodName).getDefaultImplementation();
626                         if(defaultImplementation == null)
627                             errorLog.log(instanceAst.location, "Method " + methodName + " is not defined.");
628                         else
629                             methodImplementations.put(methodName, 
630                                     new MethodImplementation(defaultImplementation, true));
631                     }
632                 
633                 JavaTypeInstanceConstructor generator = new JavaTypeInstanceConstructor(javaName, instance, instanceContext);
634                 if(instanceContext.length == 0)
635                     generator.setHasStaticInstance(true);
636                 
637                 TypeClassInstance typeClassInstance = 
638                         new TypeClassInstance(instanceAst.location, typeClass, generator,
639                                 generator.getTypeParameters(),
640                                 instanceContext, instance, methodImplementations,
641                                 javaName);
642                 
643                 generator.setInstance(typeClassInstance);
644                 
645                 module.addTypeClassInstance(typeClassCon, typeClassInstance);
646             } catch(RuntimeException e) {
647                 errorLog.setExceptionPosition(instanceAst.location);
648                 throw e;
649             }
650         }
651         
652         // Generate superclass functions
653         for(ArrayList<TypeClassInstance> instanceArray : module.getTypeInstances().values())
654             for(TypeClassInstance instance : instanceArray) {
655                 try {
656                     TypeClass typeClass = instance.typeClass;
657                     int superCount = typeClass.context.length;
658                     
659                     instance.superExpressions = new SCLValue[superCount];
660                     for(int i=0;i<superCount;++i) {
661                         TPred type = (TPred)typeClass.context[i]
662                                 .replace(typeClass.parameters, instance.instance.parameters);
663                         SCLValue value = new SCLValue(Name.create(moduleName, 
664                                 instance.javaName.substring(instance.javaName.indexOf('$')+1) + "_super" + i));
665                         //value.addProperty(PrivateProperty.INSTANCE);
666                         module.addValue(value);
667                         Expression expression = new EGetConstraint(instance.location, type);
668                         value.setExpression(expression);
669                         value.setType(Types.forAll(instance.generatorParameters, Types.constrained(instance.context, type)));
670                         value.getProperties().add(new InlineProperty(instance.context.length, 0xffffffff));
671                         //TypeUnparsingContext tuc = new TypeUnparsingContext();
672                         // TODO error handling
673                         instance.superExpressions[i] = value;
674                     }
675                 } catch(RuntimeException e) {
676                     errorLog.setExceptionPosition(instance.getLocation());
677                     throw e;
678                 }
679             }
680     }
681     
682     public void processJavaMethods(ArrayList<JavaMethodDeclaration> javaMethodDeclarations) {
683         for(JavaMethodDeclaration javaMethod : javaMethodDeclarations) {
684             String name = javaMethod.methodName.name;
685             String javaName = name;
686             ArrayList<DAnnotationAst> annotations = 
687                     valueDefinitionsAst.getAnnotations(name);
688             boolean isPrivate = false;
689             if(annotations != null) {
690                 for(DAnnotationAst annotation : annotations)
691                     if(annotation.id.text.equals("@JavaName")) {
692                         String temp = AnnotationUtils.processStringAnnotation(errorLog, annotation);
693                         if(temp != null)
694                             javaName = temp;
695                     }
696                     else if(annotation.id.text.equals("@private")) {
697                         AnnotationUtils.processTagAnnotation(errorLog, annotation);
698                         isPrivate = true;
699                     }
700             }
701             
702             Type type = createTypeTranslationContext().toType(javaMethod.type);
703
704             CallJava callJava = resolveMethod(
705                     javaMethod.location,
706                     javaMethod.className,
707                     javaName,
708                     type);
709             if(callJava != null) {
710                 NameExistenceChecks.checkIfValueExists(errorLog, javaMethod.location,
711                         importedEnvironment, name);
712                 SCLValue value = module.addValue(name, callJava);
713                 value.definitionLocation = javaMethod.methodName.location;
714                 if(isPrivate)
715                     value.addProperty(PrivateProperty.INSTANCE);
716             }
717         }
718     }
719     
720     public void processRulesets(ArrayList<DRulesetAst> rulesetsAst) {
721         for(DRulesetAst ruleset : rulesetsAst) {
722             String constructorName = "create" + ruleset.name;
723             supplementedTypeAnnotations.add(new SupplementedValueType(ruleset.location, constructorName, Types.functionE(Types.PUNIT, Types.PROC, ruleset.type)));
724             try {
725                 valueDefinitionsAst.add(new DValueAst(new EVar(constructorName), new EPreCHRRulesetConstructor(ruleset)));
726             } catch (NotPatternException e) {
727                 throw new InternalCompilerError(ruleset.location, e);
728             }
729         }
730     }
731     
732     /**
733      * Convert a java class method into a {@link CallJava} instance.
734      * Compilation errors are logged for failures in finding the named class or in accessing the method.
735      * The return value for errors is {@code null}.
736      * 
737      * @param loc  SCL source location
738      * @param className  Name of the class
739      * @param methodName  Name of the method
740      * @param type  The expected SCL type of the method 
741      * @return  A new JavaCall instance, or null if the given method can not be instantiated.
742      */
743     private CallJava resolveMethod(long loc,
744             String className, String methodName, Type type) {
745         // Resolve class
746         ClassRef classRef = classRefs.get(className);
747         if(classRef == null) {
748             if(classRefs.containsKey(className))
749                 return null;
750             classRef = javaReferenceValidator.getClassRef(className);
751             classRefs.put(className, classRef);
752             if(classRef == null) {
753                 errorLog.log(loc, "Didn't find class " + className + ".");
754                 return null;
755             }
756             if(!javaReferenceValidator.isPublic(classRef.getClass())) {
757                 errorLog.log(loc, "Class " + className + " is not public.");
758                 return null;
759             }
760             
761         }
762         
763         // Resolve method
764         List<MethodRef> methodRefs = classRef.getMethodRefs(methodName);
765         if(methodRefs.isEmpty()) {
766             errorLog.log(loc, "Didn't find any public method or field with name '" + methodName + "' from class " + className + ".");
767             return null;
768         }
769         
770         ArrayList<CallJava> candidates = new ArrayList<CallJava>(2); 
771         for(MethodRef methodRef : methodRefs) {
772             CallJava candidate = matchType(methodRef, type);
773             if(candidate != null)
774                 candidates.add(candidate);
775         }
776
777         if(candidates.isEmpty()) {
778             StringBuilder b = new StringBuilder();
779             b.append("Didn't find any public method or field matching the type " + type + ". The following methods and fields were tried:");
780             for(MethodRef methodRef : methodRefs) {
781                 b.append("\n    ");
782                 b.append(methodRef);
783             }
784             b.append("\nbut expected something like:");
785             {
786                 MultiFunction mFun = Types.matchFunction(type);
787                 b.append("\n    public static ");
788                 b.append(javaTypeTranslator.toTypeDesc(mFun.returnType).getFullName()).append(' ').append(methodName).append('(');
789                 boolean first = true;
790                 for(Type parameter : mFun.parameterTypes) {
791                     if(first)
792                         first = false;
793                     else
794                         b.append(", ");
795                     b.append(javaTypeTranslator.toTypeDesc(parameter).getFullName());
796                 }
797                 b.append(')');
798             }
799             errorLog.log(loc, b.toString());
800             return null;
801         }
802         else if(candidates.size() == 1)
803             return candidates.get(0);
804         else {
805             // Try to find the best match
806             ArrayList<CallJava> bestCandidates = new ArrayList<CallJava>(candidates.size());
807             loop: for(CallJava candidate : candidates) {
808                 Iterator<CallJava> it = bestCandidates.iterator();
809                 while(it.hasNext()) {
810                     CallJava b = it.next();
811                     switch(candidate.compareTo(javaReferenceValidator, b)) {
812                     case CallJava.LESS:
813                     case CallJava.EQUAL:
814                         continue loop;
815                     case CallJava.GREATER:
816                         it.remove();
817                         break;
818                     case CallJava.INCOMPARABLE:
819                         break;
820                     }
821                 }
822                 bestCandidates.add(candidate);
823             }
824             
825             if(bestCandidates.size() == 1) {
826                 // System.out.println("Choose: " + bestCandidates.get(0).getMethodRef());
827                 return bestCandidates.get(0);
828             }
829             else { 
830                 StringBuilder b = new StringBuilder();
831                 b.append("Found more than one incomparable public methods the type " + type + ":");
832                 for(CallJava callJava : bestCandidates) {
833                     b.append("\n    ");
834                     b.append(callJava.getMethodRef());
835                 }
836                 errorLog.log(loc, b.toString());
837                 return null;
838             }
839         }
840     }
841
842     private CallJava matchType(MethodRef methodRef, Type type) {
843         //System.out.println("-----------------------------------------------------");
844         //System.out.println("method: " + methodRef);
845         //System.out.println("type: " + type);
846
847         type = Types.canonical(type);
848         while(type instanceof TForAll)
849             type = Types.canonical(((TForAll)type).type);
850             
851         TypeDesc[] expectedParameterTypes = methodRef.getParameterTypes();
852         
853         ArrayList<Type> parameterTypes = new ArrayList<Type>();
854         Type effect = Types.NO_EFFECTS;
855         Type returnType = type;
856         
857         StackItem[] stackItems = new StackItem[expectedParameterTypes.length];
858         TIntArrayList unresolvedItems = new TIntArrayList();
859         
860         loop:
861         for(int i=0;i<expectedParameterTypes.length;++i) {
862             Type parameterType;
863             TypeDesc providedParameterType;
864             do {
865                 if(effect != Types.NO_EFFECTS || !(returnType instanceof TFun)) {
866                     while(i < expectedParameterTypes.length)
867                         unresolvedItems.add(i++);
868                     break loop;
869                 }
870                 TFun fun = (TFun)returnType;
871                 parameterType = Types.canonical(fun.domain);
872                 parameterTypes.add(parameterType);
873                 effect = Types.canonical(fun.effect);
874                 returnType = Types.canonical(fun.range);
875                 providedParameterType = javaTypeTranslator.toTypeDesc(parameterType);
876             } while(providedParameterType.equals(TypeDesc.VOID));
877             
878             while(true) {
879                 TypeDesc expectedParameterType = expectedParameterTypes[i];
880                 if(javaReferenceValidator.isAssignableFrom(expectedParameterType,
881                         providedParameterType)) {
882                     stackItems[i] = new ParameterStackItem(
883                             parameterTypes.size()-1, 
884                             parameterType);
885                     break;
886                 }
887                 else
888                     unresolvedItems.add(i++);
889                 if(i == expectedParameterTypes.length) {
890                     parameterTypes.remove(parameterTypes.size()-1);
891                     returnType = Types.functionE(parameterType, effect, returnType);
892                     break;
893                 }
894             } 
895         }
896         //System.out.println("returnType: " + returnType);
897         if(!unresolvedItems.isEmpty()) {
898             ArrayList<TCon> concreteEffects = new ArrayList<TCon>();
899             effect.collectConcreteEffects(concreteEffects);
900             
901             for(TCon eff : concreteEffects) {
902                 EffectConstructor effC = compilationContext.environment.getEffectConstructor(eff);
903                 for(ThreadLocalVariable var : effC.getThreadLocalVariables()) {
904                     for(int i=0;i<unresolvedItems.size();++i) {
905                         int id = unresolvedItems.get(i);
906                         if(!expectedParameterTypes[id].equals(TypeDesc.OBJECT) &&
907                                 javaReferenceValidator.isAssignableFrom(expectedParameterTypes[id], var.type)) {
908                             stackItems[id] = new ThreadLocalStackItem(var.variableName, var.type);
909                             unresolvedItems.removeAt(i);
910                             --i;
911                         }
912                     }
913                 }
914             }
915             
916             if(!unresolvedItems.isEmpty())
917                 return null;
918             /*System.out.print("Unresolved: ");
919             boolean first = true;
920             for(int i=0;i<unresolvedItems.size();++i) {
921                 if(first)
922                     first = false;
923                 else
924                     System.out.print(", ");
925                 System.out.print(expectedParameterTypes[unresolvedItems.get(i)]);
926             }
927             System.out.println();*/            
928         }   
929         OutputFilter filter = null;
930         {
931             TypeDesc providedReturnType = methodRef.getReturnType();
932             if(!providedReturnType.equals(Constants.FUNCTION)) {
933                 while(returnType instanceof TFun && effect == Types.NO_EFFECTS) {
934                     TFun fun = (TFun)returnType;
935                     Type parameterType = Types.canonical(fun.domain);
936                     if(!javaTypeTranslator.toTypeDesc(parameterType).equals(TypeDesc.VOID))
937                         return null;                    
938                     parameterTypes.add(parameterType);
939                     effect = Types.canonical(fun.effect);
940                     returnType = Types.canonical(fun.range);
941                 }
942             }
943             TypeDesc expectedReturnType = 
944                     javaTypeTranslator.toTypeDesc(returnType);
945             if(!javaReferenceValidator.isAssignableFrom(expectedReturnType,
946                     providedReturnType)) {
947                 if(expectedReturnType.equals(TypeDesc.VOID)) {
948                     if(providedReturnType.equals(TypeDesc.DOUBLE) || providedReturnType.equals(TypeDesc.LONG))
949                         filter = Pop2OutputFilter.INSTANCE;
950                     else
951                         filter = PopOutputFilter.INSTANCE;
952                 }
953                 else if(expectedReturnType.equals(Constants.LIST)
954                         && providedReturnType.equals(Constants.COLLECTION))
955                     filter = ConvertToListFilter.INSTANCE;
956                 else
957                     return null;
958             }
959         }
960         
961         CallJava result = new CallJava(
962                 Types.freeVarsArray(type),
963                 effect,
964                 returnType,
965                 parameterTypes.toArray(new Type[parameterTypes.size()]),
966                 stackItems, 
967                 methodRef,
968                 filter);
969         //System.out.println(result.getType());
970         return result;
971     }
972
973     public void processMappingRelations(ArrayList<DMappingRelationAst> mappingRelationsAst) {
974         for(DMappingRelationAst mappingRelation : mappingRelationsAst) {
975             TypeAst[] parameterTypesAst = mappingRelation.parameterTypes;
976             Type[] parameterTypes = new Type[parameterTypesAst.length];
977             TypeTranslationContext typeTranslationContext = createTypeTranslationContext();
978             for(int i=0;i<parameterTypes.length;++i)
979                 parameterTypes[i] = parameterTypesAst[i].toType(typeTranslationContext, Kinds.STAR);
980             MappingRelation mRel = 
981                     new MappingRelation(Name.create(moduleName, mappingRelation.name), parameterTypes);
982             mRel.location = mappingRelation.location;
983             if(module.addMappingRelation(mRel))
984                 errorLog.log(mappingRelation.location, "Mapping relation " + mappingRelation.name + 
985                         " has already been defined.");
986         }
987     }
988
989     THashMap<String, DRuleAst> ruleAstMap = new THashMap<String, DRuleAst>();
990     
991     public void processRules(ArrayList<DRuleAst> rulesAst) {
992         // Find implied mapping relations
993         for(DRuleAst ruleA : rulesAst) {
994             ArrayList<Query> whereSection = ruleA.getSections().get("where");
995             if(whereSection != null)
996                 for(Query query : whereSection) {
997                     if(!(query instanceof QPreGuard))
998                         continue;
999                     QPreGuard guard = (QPreGuard)query;
1000                     if(!(guard.guard instanceof EApply))
1001                         continue;
1002                     EApply apply = (EApply)guard.guard;
1003                     if(!(apply.getFunction() instanceof EVar))
1004                         continue;
1005
1006                     String name = ((EVar)apply.getFunction()).name;
1007                     if(module.getMappingRelation(name) != null)
1008                         continue;
1009
1010                     int arity = apply.getParameters().length;
1011                     Type[] parameterTypes = new Type[arity];
1012                     for(int i=0;i<arity;++i)
1013                         parameterTypes[i] = Types.metaVar(Kinds.STAR);
1014                     MappingRelation mRel = 
1015                             new MappingRelation(Name.create(moduleName, name), parameterTypes);
1016                     mRel.location = query.location;
1017                     module.addMappingRelation(mRel);
1018                 }
1019             if(ruleAstMap.put(ruleA.name, ruleA) != null)
1020                 errorLog.log(ruleA.location, "Rule " + ruleA.name + 
1021                         " has already been defined.");
1022         }
1023         
1024         // 
1025         for(String ruleName : ruleAstMap.keySet())
1026             processRule(ruleName);
1027     }
1028     
1029     private TransformationRule processRule(String ruleName) {
1030         TransformationRule rule = module.getRule(ruleName);
1031         if(rule != null)
1032             return rule;
1033         
1034         DRuleAst ruleAst = ruleAstMap.get(ruleName);
1035         if(ruleAst.alreadyProcessing) {
1036             errorLog.log(ruleAst.location, "Cyclic chain of rule extensions.");
1037             return null;
1038         }
1039         
1040         TransformationRule[] extendsRules;
1041         int length = ruleAst.extendsNames.length;
1042         if(length == 0)
1043             extendsRules = TransformationRule.EMPTY_ARRAY;
1044         else {
1045             extendsRules = new TransformationRule[length];
1046             for(int i=0;i<length;++i) {
1047                 try {
1048                     String extendsName = ruleAst.extendsNames[i];
1049                     TransformationRule extendsRule;
1050                     if(ruleAstMap.containsKey(extendsName))
1051                         extendsRule = processRule(extendsName);
1052                     else {
1053                         extendsRule = Environments.getRule(compilationContext.environment, extendsName);
1054                         if(extendsRule == null)
1055                             errorLog.log(ruleAst.location,
1056                                     "Couldn't resolve rule name " + extendsName + ".");
1057                     }
1058                     extendsRules[i] = extendsRule;
1059                 } catch(AmbiguousNameException e) {
1060                     errorLog.log(ruleAst.location, e.getMessage());
1061                 }
1062             }
1063         }
1064         
1065         final THashMap<SectionName, Query[]> sections = new THashMap<SectionName, Query[]>();
1066
1067         final TranslationContext context = createTranslationContext();
1068         if(length > 0) {
1069             THashMap<String, Variable> variables = context.getVariables();
1070             for(TransformationRule extendsRule : extendsRules) {
1071                 if(extendsRule == null)
1072                     continue;
1073                 for(Variable var : extendsRule.variables)
1074                     if(variables.put(var.getName(), var) != null) {
1075                         errorLog.log(ruleAst.location, 
1076                                 "Variable " + var.getName() + " is defined in more than one base rule, which is not currently allowed.");
1077                     }
1078             }
1079         }
1080         context.pushExistentialFrame();
1081         ruleAst.getSections().forEachEntry(new TObjectObjectProcedure<String, ArrayList<Query>>() {
1082             @Override
1083             public boolean execute(String sectionNameString, ArrayList<Query> queries) {
1084                 Query[] resolvedQueries = new Query[queries.size()];
1085                 for(int i=0;i<resolvedQueries.length;++i)
1086                     resolvedQueries[i] = queries.get(i).resolve(context);
1087
1088                 SectionName sectionName = SectionName.getSectionName(sectionNameString);
1089                 if(sectionName == null)
1090                     context.getErrorLog().log(queries.get(0).location,
1091                             "Invalid section name " + sectionNameString + ".");
1092                 else
1093                     sections.put(sectionName, resolvedQueries);
1094                 return true;
1095             }
1096         });
1097         
1098         Variable[] variables = context.getVariables().values().toArray(new Variable[context.getVariables().size()]);
1099
1100         rule = new TransformationRule(ruleAst.isAbstract,
1101                 Name.create(moduleName, ruleAst.name),
1102                 extendsRules,
1103                 sections, variables);
1104         rule.location = ruleAst.location;
1105         module.addRule(rule);
1106         return rule;
1107     }
1108
1109     public void addDataTypesToEnvironment() {
1110         for(StandardTypeConstructor dataType : dataTypes) {
1111             int constructorTag = 0;
1112             for(Constructor constructor : dataType.constructors) {
1113                 SCLValue value = new SCLValue(constructor.name);
1114                 SCLConstructor sclConstructor = 
1115                         new SCLConstructor(
1116                                 constructor.name.name,
1117                                 constructor.javaName, 
1118                                 constructor.getTypeVariables(),
1119                                 constructorTag++,
1120                                 constructor.getReturnType(),
1121                                 constructor.fieldNames == null 
1122                                         ? SCLConstructor.DEFAULT_FIELD_NAMES[constructor.getParameterTypes().length] 
1123                                         : constructor.fieldNames,
1124                                 constructor.recordFieldNames,
1125                                 constructor.getParameterTypes());
1126                 if(dataType.constructors.length == 1 && (
1127                         dataType.getTypeDesc() == null ||
1128                         (dataType.constructors[0].javaName != null &&
1129                         dataType.constructors[0].javaName.equals(MethodBuilderBase.getClassName(dataType.getTypeDesc())))))
1130                     sclConstructor.setOnlyConstructor(true);
1131                 value.setValue(sclConstructor);
1132                 value.setType(constructor.getType());
1133                 
1134                 NameExistenceChecks.checkIfValueExists(errorLog, constructor.loc,
1135                         importedEnvironment, constructor.name.name);
1136                 if(module.addValue(value)) {
1137                     errorLog.log(constructor.loc,
1138                             "Value " + constructor.name.name + " is already defined.");
1139                 }
1140             }
1141         }
1142     }
1143     
1144     public void addTypeClassesToEnvironment() {
1145         for(TypeClass typeClass : module.getTypeClasses()) {
1146             for(TypeClassMethod method : typeClass.methods.values()) {
1147                 SCLValue value = method.createValue();
1148                 value.definitionLocation = method.location;
1149                 NameExistenceChecks.checkIfValueExists(errorLog, Locations.NO_LOCATION,
1150                         importedEnvironment, value.getName().name);
1151
1152                 if(module.addValue(value)) {
1153                     String name = method.getName();
1154                     long location = Locations.NO_LOCATION;
1155                     ArrayList<DValueAst> definitions = valueDefinitionsAst.getDefinition(name);
1156                     if(definitions != null && !definitions.isEmpty())
1157                         location = definitions.get(0).location;
1158                     errorLog.log(location, "Value " + name + " is already defined.");
1159                 }
1160             }
1161         }
1162     }
1163     
1164     public void preprocessValueDefinitions(ArrayList<DValueTypeAst> typeAnnotationsAst) {
1165         for(String name : valueDefinitionsAst.getValueNames()) {
1166             SCLValue value = new SCLValue(Name.create(moduleName, name));
1167             
1168             long location = valueDefinitionsAst.getLocation(name);
1169             NameExistenceChecks.checkIfValueExists(errorLog, location,
1170                     importedEnvironment, value.getName().name);
1171             value.definitionLocation = location;
1172             if(module.addValue(value))
1173                 errorLog.log(location, "Value " + name + " is already defined.");
1174         }
1175         for(DValueTypeAst valueTypeAst : typeAnnotationsAst)
1176             for(EVar name : valueTypeAst.names) {
1177                 SCLValue value = module.getValue(name.name); 
1178                 if(value == null) {
1179                     errorLog.log(valueTypeAst.location, name.name + " is not defined.");
1180                     value = new SCLValue(Name.create(moduleName, name.name));
1181                     module.addValue(value);
1182                 }
1183                 value.definitionLocation = name.location;
1184             }
1185         for(String name : relationDefinitionsAst.getRelationNames()) {
1186             ConcreteRelation relation = new ConcreteRelation(name);
1187             module.addRelation(name, relation);
1188         }
1189     }
1190     
1191     public void addValueDefinitionsToEnvironment(ArrayList<DValueTypeAst> typeAnnotationsAst) {
1192         THashMap<String, DValueTypeAst> typeMap = new THashMap<String, DValueTypeAst>();
1193         for(DValueTypeAst valueTypeAst : typeAnnotationsAst)
1194             for(EVar name : valueTypeAst.names) {
1195                 if(typeMap.containsKey(name.name))
1196                     errorLog.log(valueTypeAst.location, "Type of "+name.name+" has already been declared in this module.");
1197                 else
1198                     typeMap.put(name.name, valueTypeAst);
1199             }
1200         
1201         THashMap<String, EVar> exportMap = null;
1202         if(moduleHeader != null && moduleHeader.export != null) {
1203             exportMap = new THashMap<String, EVar>();
1204             for(EVar export : moduleHeader.export)
1205                 if(exportMap.put(export.name, export) != null)
1206                     errorLog.log(export.location, "The symbol " + export.name + " is exported multiple times.");
1207         }
1208         
1209         for(String name : valueDefinitionsAst.getValueNames()) {
1210             ArrayList<DValueAst> defs = valueDefinitionsAst.getDefinition(name);
1211             try {
1212                 SCLValue value = module.getValue(name);
1213                 TranslationContext context = createTranslationContext();
1214                 Expression expression = context.translateCases2(defs);
1215                 value.setExpression(expression);
1216                 
1217                 DValueTypeAst valueTypeAst = typeMap.remove(name);
1218                 if(valueTypeAst != null)
1219                     value.setType(Types.closure(context.toType(valueTypeAst.type)));
1220                 
1221                 ArrayList<DAnnotationAst> annotations = valueDefinitionsAst.getAnnotations(name);
1222                 if(annotations != null)
1223                     for(DAnnotationAst annotation : annotations) {
1224                         handleAnnotation(value, defs, annotation);
1225                     }
1226                 if(exportMap != null && exportMap.remove(name) == null)
1227                     value.addProperty(PrivateProperty.INSTANCE);
1228             } catch(RuntimeException e) {
1229                 errorLog.setExceptionPosition(defs.get(0).location);
1230                 throw e;
1231             }
1232         }
1233         if(exportMap != null)
1234             for(EVar export : exportMap.values())
1235                 errorLog.log(export.location, "The symbol " + export.name + " is not defined in the module.");
1236         for(String name : relationDefinitionsAst.getRelationNames()) {
1237             ArrayList<DRelationAst> definitions = relationDefinitionsAst.getDefinition(name);
1238             if(definitions.size() > 1) {
1239                 errorLog.log(definitions.get(1).location,
1240                         "Does not yet support definition of relations by more than one rule.");
1241                 continue;
1242             }
1243             
1244             DRelationAst definition = definitions.get(0);
1245             ConcreteRelation relation = (ConcreteRelation)module.getRelation(name);
1246             relation.location = definition.location;
1247             TranslationContext context = createTranslationContext();
1248             definition.translateTo(context, relation);
1249         }
1250     }
1251     
1252     private TranslationContext createTranslationContext() {
1253         return new TranslationContext(compilationContext, null);
1254     }
1255     
1256     private void handleAnnotation(SCLValue value, ArrayList<DValueAst> defs, DAnnotationAst annotation) {
1257         if(annotation.id.text.equals("@macro")) {
1258             value.setMacroRule(new StandardMacroRule());
1259         }
1260         else if(annotation.id.text.equals("@inline")) {
1261             try {
1262                 int arity = defs.get(0).lhs.getFunctionDefinitionPatternArity();
1263                 int phaseMask = 0xffffffff;
1264                 if(annotation.parameters.length > 0) {
1265                     phaseMask = Integer.parseInt(((EIntegerLiteral)annotation.parameters[0]).getValue());
1266                 }
1267                 value.addProperty(new InlineProperty(arity, phaseMask));
1268             } catch(NotPatternException e) {
1269                 errorLog.log(annotation.location, "Inline annotation is invalid: this is not a function.");
1270             }
1271         }
1272         else if(annotation.id.text.equals("@private")) {
1273             if(moduleHeader != null && moduleHeader.export != null)
1274                 errorLog.log(annotation.location, "Annotation @private is not used when module header contains export property.");
1275             value.addProperty(PrivateProperty.INSTANCE);
1276         }
1277         else if(annotation.id.text.equals("@deprecated")) {
1278             String description = "";
1279             if(annotation.parameters.length > 0) {
1280                 if(annotation.parameters.length > 1)
1281                     errorLog.log(annotation.location, "Invalid number of parameters, expected one string.");
1282                 else {
1283                     String temp = AnnotationUtils.extractString(annotation.parameters[0]);
1284                     if(temp == null)
1285                         errorLog.log(annotation.location, "Invalid parameter, expected one string.");
1286                     else
1287                         description = temp;
1288                 }
1289             }
1290             value.addProperty(new DeprecatedProperty(description));
1291         }
1292         else
1293             errorLog.log(annotation.location, "Unknown annotation.");
1294     }
1295
1296     public void addSupplementedTypeAnnotationsToEnvironment() {
1297         for(SupplementedValueType valueType : supplementedTypeAnnotations) {
1298             Type type = Types.closure(valueType.type);
1299             String name = valueType.name;
1300             SCLValue value = module.getValue(name);
1301             if(value == null)
1302                 errorLog.log(valueType.position,
1303                         name + " is not defined.");
1304             else if(value.getType()==null)
1305                 value.setType(type);
1306             else
1307                 errorLog.log(valueType.position, 
1308                         "Type of "+name+" has already been declared in this module.");
1309         }
1310     }
1311     
1312     public void addFixityToEnvironment(ArrayList<DFixityAst> fixityAst) {
1313         for(DFixityAst fixity : fixityAst) {
1314             for(EVar symbol : fixity.symbols) {
1315                 String name = symbol.name;
1316                 SCLValue value = module.getValue(name);
1317                 if(value == null)
1318                     errorLog.log(symbol.location,
1319                             name + " is not defined.");
1320                 else
1321                     value.setPrecedence(fixity.precedence);
1322             }
1323         }
1324     }
1325
1326     public void addCoverageBranchPoints() {
1327         branchPoints = new THashMap<String, BranchPoint[]>();
1328         BranchPointInjector injector = new BranchPointInjector(); 
1329         for(String valueName : valueDefinitionsAst.getValueNames()) {
1330             for(DValueAst valueAst : valueDefinitionsAst.getDefinition(valueName))
1331                 valueAst.value = injector.injectBranchPoint(valueAst.value);
1332             branchPoints.put(valueName, injector.getAndClearBranchPoints());
1333         }
1334     }
1335 }