001/*
002 * Copyright (c) 2012-2021 Institut National des Sciences Appliquées de Lyon (INSA Lyon) and others
003 *
004 * This program and the accompanying materials are made available under the
005 * terms of the Eclipse Public License 2.0 which is available at
006 * http://www.eclipse.org/legal/epl-2.0.
007 *
008 * SPDX-License-Identifier: EPL-2.0
009 */
010
011package gololang.ir;
012
013import org.eclipse.golo.compiler.PackageAndClass;
014
015/**
016 * An import of a Golo or Java module, class or package.
017 *
018 * <p>Represents golo code such as
019 * <pre class="listing"><code class="lang-golo" data-lang="golo">
020 * import java.util.Collections
021 * </code></pre>
022 */
023public final class ModuleImport extends GoloElement<ModuleImport> implements ToplevelGoloElement {
024
025  private final PackageAndClass packageAndClass;
026  private final boolean implicit;
027
028  private ModuleImport(PackageAndClass packageAndClass, boolean implicit) {
029    super();
030    this.packageAndClass = packageAndClass;
031    this.implicit = implicit;
032  }
033
034  /**
035   * Create an implicit module import.
036   *
037   * <p>
038   * Implicit imports are ones automatically added to a module, contrary to ones added by the developer.
039   * If the given name is already a module import, it is returned unchanged if already implicit; a new one is created
040   * otherwise.
041   * The name to import is derived using {@link PackageAndClass#of(Object)}.
042   */
043  public static ModuleImport implicit(Object name) {
044    if (name instanceof ModuleImport) {
045      ModuleImport mod = (ModuleImport) name;
046      if (mod.implicit) {
047        return mod;
048      }
049      return new ModuleImport(mod.packageAndClass, true);
050    }
051    return new ModuleImport(PackageAndClass.of(name), true);
052  }
053
054  /**
055   * Create a module import.
056   *
057   * <p>
058   * If the given name is already a module import, it is returned unchanged.
059   * The name to import is derived using {@link PackageAndClass#of(Object)}.
060   */
061  public static ModuleImport of(Object name) {
062    if (name instanceof ModuleImport) {
063      return (ModuleImport) name;
064    }
065    return new ModuleImport(PackageAndClass.of(name), false);
066  }
067
068  protected ModuleImport self() { return this; }
069
070  /**
071   * Returns the {@link PackageAndClass} of the module to be imported.
072   */
073  public PackageAndClass getPackageAndClass() {
074    return packageAndClass;
075  }
076
077  /**
078   * Checks if this import is implicit.
079   * <p>
080   * Implicit imports are ones automatically added to a module, contrary to ones added by the developer.
081   */
082  public boolean isImplicit() {
083    return this.implicit;
084  }
085
086  /**
087   * {@inheritDoc}
088   */
089  @Override
090  public String toString() {
091    return "ModuleImport{"
092        + "packageAndClass=" + packageAndClass
093        + (implicit ? ", implicit" : "")
094        + '}';
095  }
096
097  /**
098   * {@inheritDoc}
099   * <p>
100   * Equality ignores the implicit status.
101   * Therefore, adding explicitly a import that is already implicit is a noop.
102   */
103  @Override
104  public boolean equals(Object o) {
105    if (this == o) { return true; }
106    if (o == null || getClass() != o.getClass()) { return false; }
107
108    ModuleImport that = (ModuleImport) o;
109    return packageAndClass.equals(that.packageAndClass);
110  }
111
112  /**
113   * {@inheritDoc}
114   */
115  @Override
116  public int hashCode() {
117    return packageAndClass.hashCode();
118  }
119
120  /**
121   * {@inheritDoc}
122   */
123  @Override
124  public void accept(GoloIrVisitor visitor) {
125    visitor.visitModuleImport(this);
126  }
127
128  /**
129   * {@inheritDoc}
130   */
131  @Override
132  protected void replaceElement(GoloElement<?> original, GoloElement<?> newElement) {
133    throw cantReplace();
134  }
135}