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