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