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