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