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