/* * Copyright 2010 Pablo Arrighi, Alex Concha, Miguel Lezama for version 1. * Copyright 2013 Pablo Arrighi, Miguel Lezama, Kevin Mazet for version 2. * * This file is part of GOOL. * * GOOL is free software: you can redistribute it and/or modify it under the terms of the GNU * General Public License as published by the Free Software Foundation, version 3. * * GOOL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License along with GOOL, * in the file COPYING.txt. If not, see <http://www.gnu.org/licenses/>. */ package gool.ast.core; import gool.ast.type.IType; import gool.ast.type.TypeClass; import gool.generator.GoolGeneratorController; import gool.generator.common.CodeGeneratorNoVelocity; import gool.generator.common.CodePrinter; import gool.generator.common.Platform; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; /** * This captures classes in the intermediate language. For each object member of * ClassDef the compiler will have to generate a separate file containing the * code of the class in the target language. */ public class ClassDef extends Dependency { /** * Class' dependencies (imports). */ private List<Dependency> dependencies = new ArrayList<Dependency>(); /** * Class' modifiers. */ private Collection<Modifier> modifiers = new HashSet<Modifier>(); /** * Class' name. */ private String name; /** * List of fields. */ private List<Field> fields = new ArrayList<Field>(); /** * List of methods. */ private List<Meth> methods = new ArrayList<Meth>(); /** * List of implemented interfaces. */ private List<IType> interfaces = new ArrayList<IType>(); /** * Parent class. */ private IType parentClass; /** * The class' type. */ private IType classType; /** * The destination platform. */ private Platform platform; /** * Flag to know if it is an interface. */ private boolean isInterface; /** * Flag to know if it is the main class. */ private boolean isMainClass; /** * Flag to know if it is a gool library class. */ private boolean isGoolLibraryClass; /** * The package used by the class. */ private Package ppackage; /** * The constructor of a "class definition". * @param modifier * : The modifier used by the class. * @param name * : The name of the class. * @param platform * : The destination platform. */ public ClassDef(Modifier modifier, String name, Platform platform) { this(name, platform); addModifier(modifier); } /** * The constructor of a "class definition". * @param name * : The name of the class. */ public ClassDef(String name) { this.name = name; setType(new TypeClass(name)); } /** * The constructor of a "class definition". * @param name * : The name of the class. * @param platform * : The destination platform. */ public ClassDef(String name, Platform platform) { this(name); this.platform = platform; } /** * Adds a new class modifier. * * @param modifier * the modifier to be added. */ public final void addModifier(Modifier modifier) { this.modifiers.add(modifier); } /** * Appends the specified method to the list of methods. * * @param method * method to be appended. */ public void addMethod(Meth method) { if (method instanceof Constructor) { method.setName(getName()); } else if (method instanceof MainMeth) { setMainClass(true); } method.setClassDef(this); methods.add(method); } /** * Appends the specified field to the list of fields. * * @param field * field to be appended. */ public void addField(Field field) { fields.add(field); } /** * Initializes the default constructor by using a list of undeclared * variables. * * @param freeVars * list of undeclared variables that are used inside the class. * @return the default constructor. */ public Constructor createDefaultConstructor() { Constructor constructor = new Constructor(); for (Field field : getFields()) { constructor.addParameter(new VarDeclaration(field)); Assign assign = new Assign(new FieldAccess(field.getType(), new This(getType()), field.getName()), new VarAccess(field)); constructor.addStatement(assign); } addMethod(constructor); return constructor; } /** * Initializes the class' fields and adds a default constructor initializing * those fields. * * @param parameters * the list of undeclared variables that are used in the class. * @return the default constructor. */ public void addFields(Collection<Dec> parameters) { for (Dec freeVar : parameters) { addField(new Field(Modifier.PRIVATE, freeVar.getName(), freeVar.getType())); } } /** * Sets the package used by the class. * @param ppackage * : The new package used by the class. */ public void setPpackage(Package ppackage) { this.ppackage = ppackage; } /** * Gets the package used by the class. * @return * The package used by the class. */ public Package getPpackage() { return ppackage; } /** * Gets the name of the package used by the class. * @return * The name of the package used by the class. */ public String getPackageName() { return ppackage == null ? "" : ppackage.getName(); } /** * Gets the list of modifiers. * * @return a list of modifiers. */ public Collection<Modifier> getModifiers() { return modifiers; } /** * Gets the class' name. * * @return the class' name. */ public final String getName() { return name; } /** * Sets the name of the class. * @param name * : The new name of the class. */ public final void setName(String name) { this.name = name; } /** * Gets the list of the constructors defined in the class. * @return * The list of the constructors defined in the class. */ public List<Constructor> getConstructors() { List<Constructor> constructors = new ArrayList<Constructor>(); for (Meth m : methods) { if (m instanceof Constructor) { constructors.add((Constructor) m); } } return constructors; } /** * Determines if the class is an interface. * @return * True if the class is an interface, else false. */ public final boolean isInterface() { return isInterface; } /** * Sets the flag to know if the class is an interface. * @param isInterface * True if the class is an interface, else false. */ public final void setIsInterface(boolean isInterface) { this.isInterface = isInterface; } /** * Gets the platform. * * @return */ public final Platform getPlatform() { return platform; } /** * Assigns the platform of the current class. * * @param platform * the platform to be assigned. */ public final void setPlatform(Platform platform) { this.platform = platform; } /** * Determines if the class is the main class. * @return * True if the class is the main class, else false. */ public final boolean isMainClass() { return isMainClass; } /** * Sets the flag to know if the class is the main class. * @param isMainClass * True if the class is the main class, else false. */ public final void setMainClass(boolean isMainClass) { this.isMainClass = isMainClass; } /** * Gets the list of fields. * * @return the list of fields. */ public final List<Field> getFields() { return fields; } /** * Gets the list of methods defined in the class. * * @return the list of methods. */ public final List<Meth> getMethods() { return methods; } /** * Adds a new interface that should be implemented by the current class. * * @param type * the type of the interface. */ public final void addInterface(IType type) { interfaces.add(type); } /** * Sets the class to inherit from. * * @param parentClass * the parent class. */ public final void setParentClass(IType parentClass) { this.parentClass = parentClass; } /** * Gets the parent class. * * @return the parent class. */ public final IType getParentClass() { return parentClass; } /** * Gets the list of interfaces implemented by the class. * * @return a list of interfaces implemented by the class. */ public final List<IType> getInterfaces() { return interfaces; } /** * Generates the target code using the specific CodePrinter related to the * class' platform. * * Instead of concatenating strings, the code generation is implemented * using velocity templates, unless the generator implements the interface * CodeGeneratorNoVelocity. * * @return the generated target code. * @throws Exception * when velocity fails to render or find the relevant template. */ public String getCode() { CodePrinter printer = getPlatform().getCodePrinter(); if (printer.getCodeGenerator() instanceof CodeGeneratorNoVelocity) return ((CodeGeneratorNoVelocity) printer.getCodeGenerator()) .printClass(this); else return printer.processTemplate("class.vm", this); } /** * Adds a field to the "class" representation. * @param fieldName * : The name of the "field" to add. * @param type * : The type of the "field" to add. */ public final void addField(String fieldName, IType type) { fields.add(new Field(Modifier.PRIVATE, fieldName, type)); } /** * Gets the type of the class definition. * @return * The class' type. */ public final IType getType() { return classType; } /** * Adds a dependency to the list of dependencies in the class definition. * @param dependency * : The dependency to add. */ public final void addDependency(Dependency dependency) { if ((dependency instanceof TypeDependency) && (((TypeDependency) dependency).getType() instanceof TypeClass) && ((TypeClass) ((TypeDependency) dependency).getType()) .getClassDef() != null && ((TypeClass) ((TypeDependency) dependency).getType()) .getClassDef().getPlatform() != null && (!((TypeClass) ((TypeDependency) dependency).getType()) .getClassDef().getPlatform().equals(getPlatform()))) { throw new IllegalArgumentException( "There should not be dependencies between classes of different platforms."); } if (dependency != null && !dependencies.contains(dependency)) { dependencies.add(0, dependency); } } /** * Gets the list of dependencies in the class definition. * @return * The list of dependencies in the class definition. */ public final List<Dependency> getDependencies() { return dependencies; } @Override public String callGetCode() { return GoolGeneratorController.generator().getCode(this); } /** * Gets a method defined in the class. * @param methName * : The name of the method to get. * @return * The method definition if exists, else return null. */ public final Meth getMethod(String methName) { for (Meth method : methods) { if (method.getName().equals(methName)) { return method; } } ; return null; } /** * Sets the class modifiers. * @param modifiers * : The new list of modifiers used by the class. */ public final void setModifiers(Collection<Modifier> modifiers) { this.modifiers = modifiers; } /** * Adds a list of dependencies to the list of dependencies * in the class definition. * @param dependencies * : The list of dependencies to be added. */ public final void addDependencies(List<Dependency> dependencies) { for (Dependency dependency : dependencies) { addDependency(dependency); } } @Override public boolean equals(Object obj) { if (!(obj instanceof ClassDef)) { return false; } return ((ClassDef) obj).getType().equals(getType()); } @Override public int hashCode() { return getType().getName().hashCode(); } /** * Sets the type of the class. * @param type * : The new class' type. */ public final void setType(IType type) { classType = type; if (type instanceof TypeClass) { ((TypeClass) classType).setClassDef(this); } } /** * Sets the flag to know if the class is an "enum" class. * @param isEnum * : True if the class is an "enum" class, else false. */ public void setIsEnum(boolean isEnum) { if (classType instanceof TypeClass) { ((TypeClass) classType).setIsEnum(isEnum); } } /** * Determines if the class is an "enum" class. * @return * True if the class is an "enum" class, else false. */ public boolean isEnum() { return (classType instanceof TypeClass) && ((TypeClass) classType).isEnum(); } /** * Sets the flag to know if it is a gool library class. * @param isGoolLibraryClass * : True if the it is a gool library class, else false. */ public void setIsGoolLibraryClass(boolean isGoolLibraryClass) { this.isGoolLibraryClass = isGoolLibraryClass; } /** * Determines if it is a gool library class. * @return * True if the it is a gool library class, else false. */ public boolean isGoolLibraryClass() { return this.isGoolLibraryClass; } }