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.SymbolGenerator;
014
015/**
016 * Represents a reference.
017 *
018 * <p>A reference is ether a variable (as defined by <code class="lang-golo">var answer = 42</code>) or a constant
019 * (as defined by <code class="lang-golo">let answer = 42</code>).
020 */
021public final class LocalReference extends GoloElement<LocalReference> {
022
023  private static final SymbolGenerator REF_SYMBOLS = new SymbolGenerator("golo.ir.builders.ref");
024
025  public enum Kind {
026    CONSTANT, VARIABLE, MODULE_CONSTANT, MODULE_VARIABLE
027  }
028
029  private Kind kind = Kind.CONSTANT;
030  private final String name;
031  private boolean synthetic = false;
032  private int index = -1;
033
034  private LocalReference(String name) {
035    super();
036    this.name = name;
037  }
038
039  /**
040   * Creates a local reference.
041   *
042   * <p>If the argument is already a local reference, it is returned unchanged, otherwise, its
043   * string representation is used to name the reference.
044   *
045   * @param name the name of the reference
046   * @return a local reference to the variable named after the argument
047   */
048  public static LocalReference of(Object name) {
049    if (name instanceof LocalReference) {
050      return (LocalReference) name;
051    }
052    if (name instanceof ReferenceLookup) {
053      return new LocalReference(((ReferenceLookup) name).getName());
054    }
055    return new LocalReference(name.toString());
056  }
057
058  /**
059   * Creates a new local reference with a generated unique name.
060   */
061  public static LocalReference generate() {
062    return new LocalReference(REF_SYMBOLS.next());
063  }
064
065  public static LocalReference generate(String prefix) {
066    return new LocalReference(REF_SYMBOLS.next(prefix));
067  }
068
069  public static LocalReference create(Object name, Kind kind) {
070    return of(name).kind(kind);
071  }
072
073  protected LocalReference self() { return this; }
074
075  public Kind getKind() {
076    return kind;
077  }
078
079  public LocalReference variable() {
080    if (kind == Kind.MODULE_VARIABLE || kind == Kind.MODULE_CONSTANT) {
081      kind = Kind.MODULE_VARIABLE;
082    } else {
083      kind = Kind.VARIABLE;
084    }
085    return this;
086  }
087
088  public LocalReference moduleLevel() {
089    if (kind == Kind.CONSTANT || kind == Kind.MODULE_CONSTANT) {
090      kind = Kind.MODULE_CONSTANT;
091    } else {
092      kind = Kind.MODULE_VARIABLE;
093    }
094    return this;
095  }
096
097  public LocalReference kind(Kind k) {
098    kind = k;
099    return this;
100  }
101
102  public String getName() {
103    return name;
104  }
105
106  public LocalReference synthetic(boolean isSynthetic) {
107    this.synthetic = isSynthetic;
108    return this;
109  }
110
111  public LocalReference synthetic() {
112    return synthetic(true);
113  }
114
115  public boolean isSynthetic() {
116    return synthetic;
117  }
118
119  public boolean isModuleState() {
120    return kind == Kind.MODULE_CONSTANT || kind == Kind.MODULE_VARIABLE;
121  }
122
123  public boolean isConstant() {
124    return kind == Kind.CONSTANT || kind == Kind.MODULE_CONSTANT;
125  }
126
127  /**
128   * Internal API
129   */
130  public int getIndex() {
131    return index;
132  }
133
134  /**
135   * Internal API
136   */
137  public void setIndex(int index) {
138    this.index = index;
139  }
140
141  public LocalReference index(int index) {
142    setIndex(index);
143    return this;
144  }
145
146  /**
147   * Returns a {@link ReferenceLookup} referencing this variable.
148   */
149  public ReferenceLookup lookup() {
150    return ReferenceLookup.of(name);
151  }
152
153  /**
154   * {@inheritDoc}
155   */
156  @Override
157  public String toString() {
158    return String.format("LocalReference{kind=%s, name='%s', index=%d}", kind, name, index);
159  }
160
161  /**
162   * {@inheritDoc}
163   */
164  @Override
165  public boolean equals(Object o) {
166    if (this == o) { return true; }
167    if (o == null || getClass() != o.getClass()) { return false; }
168    LocalReference that = (LocalReference) o;
169    return kind == that.kind && name.equals(that.name);
170  }
171
172  /**
173   * {@inheritDoc}
174   */
175  @Override
176  public int hashCode() {
177    int result = kind.hashCode();
178    result = 31 * result + name.hashCode();
179    return result;
180  }
181
182  /**
183   * {@inheritDoc}
184   */
185  @Override
186  public void accept(GoloIrVisitor visitor) {
187    visitor.visitLocalReference(this);
188  }
189
190  /**
191   * {@inheritDoc}
192   */
193  @Override
194  protected void replaceElement(GoloElement<?> original, GoloElement<?> newElement) {
195    throw cantReplace();
196  }
197}