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