001/* 002 * Copyright (c) 2012-2017 Institut National des Sciences Appliquées de Lyon (INSA-Lyon) 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the Eclipse Public License v1.0 006 * which accompanies this distribution, and is available at 007 * http://www.eclipse.org/legal/epl-v10.html 008 */ 009 010package org.eclipse.golo.compiler.ir; 011 012import org.eclipse.golo.compiler.PackageAndClass; 013import org.eclipse.golo.compiler.parser.GoloASTNode; 014 015import java.util.*; 016 017import static java.util.Collections.unmodifiableSet; 018import static java.util.Collections.unmodifiableCollection; 019 020public final class GoloModule extends GoloElement implements FunctionContainer { 021 022 private final PackageAndClass packageAndClass; 023 private final ReferenceTable globalReferences; 024 private final Set<ModuleImport> imports = new LinkedHashSet<>(); 025 private final Set<GoloFunction> functions = new LinkedHashSet<>(); 026 private final Map<PackageAndClass, Augmentation> augmentations = new LinkedHashMap<>(); 027 private final Set<NamedAugmentation> namedAugmentations = new LinkedHashSet<>(); 028 private final Set<Struct> structs = new LinkedHashSet<>(); 029 private final Set<Union> unions = new LinkedHashSet<>(); 030 private final Set<LocalReference> moduleState = new LinkedHashSet<>(); 031 private GoloFunction moduleStateInitializer = null; 032 private boolean hasMain = false; 033 034 public static final Set<ModuleImport> DEFAULT_IMPORTS = unmodifiableSet(new LinkedHashSet<>(Arrays.asList( 035 new ModuleImport(PackageAndClass.fromString("gololang.Predefined"), true), 036 new ModuleImport(PackageAndClass.fromString("gololang.StandardAugmentations"), true), 037 new ModuleImport(PackageAndClass.fromString("gololang"), true), 038 new ModuleImport(PackageAndClass.fromString("java.lang"), true) 039 ))); 040 041 public static final String MODULE_INITIALIZER_FUNCTION = "<clinit>"; 042 043 public GoloModule(PackageAndClass packageAndClass) { 044 this(packageAndClass, new ReferenceTable()); 045 } 046 047 public GoloModule(PackageAndClass name, ReferenceTable references) { 048 super(); 049 this.packageAndClass = name; 050 this.globalReferences = references; 051 } 052 053 @Override 054 public GoloModule ofAST(GoloASTNode n) { 055 super.ofAST(n); 056 return this; 057 } 058 059 public PackageAndClass getPackageAndClass() { 060 return packageAndClass; 061 } 062 063 public Set<ModuleImport> getImports() { 064 Set<ModuleImport> imp = new LinkedHashSet<>(); 065 if (!structs.isEmpty() || !unions.isEmpty()) { 066 imp.add(new ModuleImport(this.getPackageAndClass().createSubPackage("types"), true)); 067 } 068 imp.addAll(imports); 069 if (this.packageAndClass.hasPackage()) { 070 imp.add(new ModuleImport(this.packageAndClass.parentPackage(), true)); 071 } 072 imp.addAll(DEFAULT_IMPORTS); 073 return imp; 074 } 075 076 public Collection<Augmentation> getAugmentations() { 077 return unmodifiableCollection(augmentations.values()); 078 } 079 080 public Set<NamedAugmentation> getNamedAugmentations() { 081 return unmodifiableSet(namedAugmentations); 082 } 083 084 public void addImport(ModuleImport moduleImport) { 085 imports.add(moduleImport); 086 makeParentOf(moduleImport); 087 } 088 089 @Override 090 public Set<GoloFunction> getFunctions() { 091 return unmodifiableSet(functions); 092 } 093 094 @Override 095 public void addFunctions(Collection<GoloFunction> functions) { 096 for (GoloFunction f : functions) { 097 this.addFunction(f); 098 } 099 } 100 101 @Override 102 public boolean hasFunctions() { 103 return !functions.isEmpty(); 104 } 105 106 public boolean hasMain() { 107 return hasMain; 108 } 109 110 @Override 111 public void addFunction(GoloFunction function) { 112 function.relinkTopLevel(globalReferences); 113 functions.add(function); 114 if (function.isMain()) { 115 hasMain = true; 116 } 117 makeParentOf(function); 118 } 119 120 public void addNamedAugmentation(NamedAugmentation augment) { 121 namedAugmentations.add(augment); 122 makeParentOf(augment); 123 } 124 125 // TODO: refactor to not return the value... 126 public Augmentation addAugmentation(Augmentation augment) { 127 if (augment.hasLocalTarget()) { 128 augment.setTargetPackage(packageAndClass + ".types"); 129 } 130 if (augmentations.containsKey(augment.getTarget())) { 131 augmentations.get(augment.getTarget()).merge(augment); 132 } else { 133 augmentations.put(augment.getTarget(), augment); 134 } 135 makeParentOf(augment); 136 return augmentations.get(augment.getTarget()); 137 } 138 139 public void addStruct(Struct struct) { 140 structs.add(struct); 141 makeParentOf(struct); 142 struct.setModuleName(getPackageAndClass()); 143 } 144 145 public GoloElement getSubtypeByName(String name) { 146 for (Struct s : structs) { 147 if (s.getName().equals(name)) { 148 return s; 149 } 150 } 151 for (Union u : unions) { 152 if (u.getName().equals(name)) { 153 return u; 154 } 155 } 156 return null; 157 } 158 159 public void addUnion(Union union) { 160 unions.add(union); 161 makeParentOf(union); 162 union.setModuleName(this.getPackageAndClass()); 163 this.addImport(new ModuleImport(union.getPackageAndClass(), true)); 164 } 165 166 public void addModuleStateInitializer(AssignmentStatement assignment) { 167 addLocalState(assignment.getLocalReference()); 168 if (moduleStateInitializer == null) { 169 moduleStateInitializer = Builders.functionDeclaration() 170 .name(MODULE_INITIALIZER_FUNCTION).synthetic() 171 .block(Builders.block().ref(globalReferences)); 172 functions.add(moduleStateInitializer); 173 } 174 moduleStateInitializer.getBlock().addStatement(assignment); 175 } 176 177 private void addLocalState(LocalReference reference) { 178 moduleState.add(reference); 179 makeParentOf(reference); 180 } 181 182 @Override 183 public void accept(GoloIrVisitor visitor) { 184 visitor.visitModule(this); 185 } 186 187 @Override 188 public void walk(GoloIrVisitor visitor) { 189 for (ModuleImport moduleImport : getImports()) { 190 moduleImport.accept(visitor); 191 } 192 for (Union union : unions) { 193 union.accept(visitor); 194 } 195 for (Struct struct : structs) { 196 struct.accept(visitor); 197 } 198 for (Augmentation augment :augmentations.values()) { 199 augment.accept(visitor); 200 } 201 for (NamedAugmentation augmentation : namedAugmentations) { 202 augmentation.accept(visitor); 203 } 204 for (LocalReference moduleState : moduleState) { 205 moduleState.accept(visitor); 206 } 207 for (GoloFunction function : new LinkedList<GoloFunction>(functions)) { 208 function.accept(visitor); 209 } 210 } 211 212 @Override 213 protected void replaceElement(GoloElement original, GoloElement newElement) { 214 throw cantReplace(); 215 } 216 217}