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