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