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}