001/* 002 * Copyright (c) 2012-2018 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 create(Object name, Kind kind) { 066 return of(name).kind(kind); 067 } 068 069 protected LocalReference self() { return this; } 070 071 public Kind getKind() { 072 return kind; 073 } 074 075 public LocalReference variable() { 076 if (kind == Kind.MODULE_VARIABLE || kind == Kind.MODULE_CONSTANT) { 077 kind = Kind.MODULE_VARIABLE; 078 } else { 079 kind = Kind.VARIABLE; 080 } 081 return this; 082 } 083 084 public LocalReference moduleLevel() { 085 if (kind == Kind.CONSTANT || kind == Kind.MODULE_CONSTANT) { 086 kind = Kind.MODULE_CONSTANT; 087 } else { 088 kind = Kind.MODULE_VARIABLE; 089 } 090 return this; 091 } 092 093 public LocalReference kind(Kind k) { 094 kind = k; 095 return this; 096 } 097 098 public String getName() { 099 return name; 100 } 101 102 public LocalReference synthetic(boolean isSynthetic) { 103 this.synthetic = isSynthetic; 104 return this; 105 } 106 107 public LocalReference synthetic() { 108 return synthetic(true); 109 } 110 111 public boolean isSynthetic() { 112 return synthetic; 113 } 114 115 public boolean isModuleState() { 116 return kind == Kind.MODULE_CONSTANT || kind == Kind.MODULE_VARIABLE; 117 } 118 119 public boolean isConstant() { 120 return kind == Kind.CONSTANT || kind == Kind.MODULE_CONSTANT; 121 } 122 123 /** 124 * Internal API 125 */ 126 public int getIndex() { 127 return index; 128 } 129 130 /** 131 * Internal API 132 */ 133 public void setIndex(int index) { 134 this.index = index; 135 } 136 137 public LocalReference index(int index) { 138 setIndex(index); 139 return this; 140 } 141 142 /** 143 * Returns a {@link ReferenceLookup} referencing this variable. 144 */ 145 public ReferenceLookup lookup() { 146 return ReferenceLookup.of(name); 147 } 148 149 /** 150 * {@inheritDoc} 151 */ 152 @Override 153 public String toString() { 154 return String.format("LocalReference{kind=%s, name='%s', index=%d}", kind, name, index); 155 } 156 157 /** 158 * {@inheritDoc} 159 */ 160 @Override 161 public boolean equals(Object o) { 162 if (this == o) { return true; } 163 if (o == null || getClass() != o.getClass()) { return false; } 164 LocalReference that = (LocalReference) o; 165 return kind == that.kind && name.equals(that.name); 166 } 167 168 /** 169 * {@inheritDoc} 170 */ 171 @Override 172 public int hashCode() { 173 int result = kind.hashCode(); 174 result = 31 * result + name.hashCode(); 175 return result; 176 } 177 178 /** 179 * {@inheritDoc} 180 */ 181 @Override 182 public void accept(GoloIrVisitor visitor) { 183 visitor.visitLocalReference(this); 184 } 185 186 /** 187 * {@inheritDoc} 188 */ 189 @Override 190 protected void replaceElement(GoloElement<?> original, GoloElement<?> newElement) { 191 throw cantReplace(); 192 } 193}