001/* 002 * Copyright (c) 2012-2017 Institut National des Sciences Appliquées de Lyon (INSA-Lyon) 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the Eclipse Public License v1.0 006 * which accompanies this distribution, and is available at 007 * http://www.eclipse.org/legal/epl-v10.html 008 */ 009 010package org.eclipse.golo.compiler.ir; 011 012import java.util.*; 013 014import static java.util.Collections.unmodifiableCollection; 015import static java.util.Collections.unmodifiableSet; 016import static org.eclipse.golo.compiler.ir.Builders.localRef; 017 018public final class ReferenceTable implements Scope { 019 020 private ReferenceTable parent; 021 private final Map<String, LocalReference> table = new LinkedHashMap<>(); 022 023 public ReferenceTable() { 024 this(null); 025 } 026 027 private ReferenceTable(ReferenceTable parent) { 028 this.parent = parent; 029 } 030 031 public ReferenceTable add(LocalReference reference) { 032 table.put(reference.getName(), reference); 033 return this; 034 } 035 036 public int size() { 037 return table.size() + (parent != null ? parent.size() : 0); 038 } 039 040 public boolean hasReferenceFor(String name) { 041 return table.containsKey(name) || parent != null && parent.hasReferenceFor(name); 042 } 043 044 public void updateFrom(GoloStatement statement) { 045 if (statement instanceof AssignmentStatement) { 046 AssignmentStatement assign = (AssignmentStatement) statement; 047 if (assign.isDeclaring()) { 048 this.add(assign.getLocalReference()); 049 } 050 } 051 if (statement instanceof LoopStatement) { 052 LoopStatement loop = (LoopStatement) statement; 053 if (loop.hasInitStatement()) { 054 this.add(loop.getInitStatement().getLocalReference()); 055 } 056 } 057 if (statement instanceof ForEachLoopStatement) { 058 ForEachLoopStatement foreach = (ForEachLoopStatement) statement; 059 for (LocalReference r : foreach.getReferences()) { 060 this.add(r); 061 } 062 } 063 } 064 065 public LocalReference get(String name) { 066 LocalReference reference = table.get(name); 067 if (reference != null) { 068 return reference; 069 } 070 if (parent != null) { 071 return parent.get(name); 072 } 073 return null; 074 } 075 076 public Set<String> ownedSymbols() { 077 return unmodifiableSet(table.keySet()); 078 } 079 080 public Collection<LocalReference> ownedReferences() { 081 return unmodifiableCollection(table.values()); 082 } 083 084 @Override 085 public void relink(ReferenceTable parent) { 086 for (LocalReference reference : parent.references()) { 087 if (this.hasReferenceFor(reference.getName())) { 088 this.remove(reference.getName()); 089 } 090 } 091 this.parent = parent; 092 } 093 094 private boolean isLinkedTo(ReferenceTable other) { 095 if (this != other && this.parent == null) { 096 return false; 097 } 098 return this == other || this.parent == other || this.parent.isLinkedTo(other); 099 } 100 101 @Override 102 public void relinkTopLevel(ReferenceTable topLevel) { 103 if (this == topLevel) { return; } 104 if (this.parent == null) { 105 this.parent = topLevel; 106 } else if (!this.isLinkedTo(topLevel) && !topLevel.isLinkedTo(this)) { 107 this.parent.relinkTopLevel(topLevel); 108 } 109 } 110 111 public Set<String> symbols() { 112 LinkedHashSet<String> localSymbols = new LinkedHashSet<>(table.keySet()); 113 if (parent != null) { 114 localSymbols.addAll(parent.symbols()); 115 } 116 return localSymbols; 117 } 118 119 public Collection<LocalReference> references() { 120 Collection<LocalReference> localReferences = new LinkedHashSet<>(table.values()); 121 if (parent != null) { 122 for (LocalReference ref : parent.references()) { 123 if (!table.containsKey(ref.getName())) { 124 localReferences.add(ref); 125 } 126 } 127 } 128 return localReferences; 129 } 130 131 public ReferenceTable fork() { 132 return new ReferenceTable(this); 133 } 134 135 public ReferenceTable flatDeepCopy(boolean turnIntoConstants) { 136 ReferenceTable referenceTable = new ReferenceTable(); 137 Set<String> tableSymbols = ownedSymbols(); 138 for (LocalReference reference : references()) { 139 String refName = reference.getName(); 140 if (reference.isModuleState()) { 141 referenceTable.add(localRef(refName).kind(reference.getKind())); 142 continue; 143 } 144 if (turnIntoConstants && !tableSymbols.contains(refName)) { 145 referenceTable.add(localRef(refName).synthetic(reference.isSynthetic())); 146 } else { 147 referenceTable.add(localRef(refName) 148 .kind(reference.getKind()) 149 .synthetic(reference.isSynthetic())); 150 } 151 } 152 return referenceTable; 153 } 154 155 public void remove(String name) { 156 table.remove(name); 157 } 158 159 @Override 160 public String toString() { 161 StringBuilder representation = new StringBuilder("ReferenceTable: {\n"); 162 for (Map.Entry<String, LocalReference> elt : table.entrySet()) { 163 representation.append(elt.getKey()).append(": ").append(elt.getValue()).append('\n'); 164 } 165 representation.append('}'); 166 if (parent != null) { 167 representation.append(" => ").append(parent.toString()); 168 } 169 return representation.toString(); 170 } 171}