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