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