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