Table.java
package Hoot.Runtime.Values;
import java.util.*;
import Hoot.Runtime.Behaviors.Scope;
import Hoot.Runtime.Behaviors.Typified;
import Hoot.Runtime.Emissions.Item;
import Hoot.Runtime.Maps.Library;
import Hoot.Runtime.Names.Primitive;
import Hoot.Runtime.Names.TypeName;
import static Hoot.Runtime.Functions.Utils.*;
import static Hoot.Runtime.Behaviors.HootRegistry.*;
import Hoot.Runtime.Emissions.NamedItem;
/**
* Maintains an ordered and index-able collection of local variables as a symbol table.
* Supports symbol lookup by name and writes variables in the order of their definition.
*
* @author nik <nikboyd@sonic.net>
* @see "Copyright 1999,2021 Nikolas S Boyd."
* @see "Permission is granted to copy this work provided this copyright statement is retained in all copies."
*/
public class Table extends NamedItem {
public Table(Scope container) { super(container); }
/**
* Maintains an indexed collection of symbols.
*/
protected Map<String, Variable> contents = emptyMap(Variable.class);
public int size() { return contents.size(); }
/**
* Maintains symbols in the order of their definition.
*/
protected List<Variable> order = emptyList(Variable.class);
public List<Variable> symbols() { return copyList(order); }
public List<Variable> definedSymbols() { return select(order, v -> !v.isEmpty()); }
@Override public boolean isEmpty() { return this.order == null || this.order.isEmpty(); }
/**
* Establishes (container) as the container for this scope.
*
* @param container the container scope.
*/
@Override public void container(Item container) {
super.container(container);
if (!isEmpty()) {
symbols().forEach(symbol -> symbol.container(container));
}
}
public Table withAll(Table table) {
table.order.forEach(v -> addSymbol(v));
return this;
}
public Table withAll(Map<String, Variable> map) {
map.values().forEach(v -> addSymbol(v));
return this;
}
public Table withAll(List<Variable> symbols) {
symbols.forEach(s -> addSymbol(s));
return this;
}
// public String createSymbol() {
// int nest = containerScope().nestLevel();
// int size = size();
// String name = "local" + nest + "_" + size;
// Variable v = new Variable(containerScope());
// v.name(name);
// v.clean();
// addSymbol(v);
// return name;
// }
protected boolean captureSymbol(Variable symbol) {
if (!symbol.isEmpty()) {
if (!contents.containsKey(symbol.name())) {
contents.put(symbol.name(), symbol);
return true;
}
}
return false;
}
/**
* Adds a new (empty) symbol to the table.
*/
public void prepareSymbol() {
if (!order.isEmpty()) {
// first capture any existing symbol
captureSymbol(currentSymbol());
}
order.add(new Variable(containerScope()));
}
/**
* Adds a new (symbol) to the table.
*
* @param symbol a named symbol.
*/
public void addSymbol(Variable symbol) {
if (captureSymbol(symbol)) {
order.add(symbol);
}
}
/**
* Returns the current symbol being defined by the compiler.
*
* @return the current symbol being defined by the compiler.
*/
public Variable currentSymbol() {
if (order.isEmpty()) {
order.add(new Variable(containerScope()));
}
return order.get(order.size() - 1);
}
/**
* Returns whether the local symbol table contains the named symbol.
*
* @param name the name of the desired symbol.
* @return whether the local symbol table contains the named symbol.
*/
public boolean containsSymbol(String name) {
return contents.containsKey(name);
}
/**
* Returns the named symbol.
*
* @param name the name of the desired symbol.
* @return the named symbol, or null if the table does not contain the named symbol.
*/
public Variable symbolNamed(String name) {
return (Variable) contents.get(name);
}
/**
* Cleans out any residue left from the parsing process and prepares the receiver for code generation.
*/
@Override
public void clean() {
super.clean();
if (order.isEmpty()) {
return;
}
Variable end = order.get(order.size() - 1);
if (end.isEmpty()) {
order.remove(end);
}
symbols().forEach(symbol -> symbol.clean());
}
/**
* Removes all the symbols from the table.
*/
public void clear() {
contents.clear();
order.clear();
}
/**
* Returns whether any of the symbols has a resolved type.
*
* @return whether any of the symbols has a resolved type.
*/
public boolean hasTypedNames() { return matchAny(symbols(), s -> !RootType().matches(s.type())); }
/**
* @return whether all of the symbols have erasable types
*/
public boolean hasErasableTypes() {
for (Variable symbol : symbols()) {
TypeName resolver = symbol.typeResolver();
if (resolver.isUnknown()) return false;
if (resolver.isEraseableType()) return true;
Typified typeFace = Library.findFace(resolver.fullName());
if (typeFace == null) return false;
if (!typeFace.isEraseableType()) return false;
}
return true;
}
/**
* Copies the symbols from the receiver to (aTable) without types.
*
* @param aTable a symbol table.
*/
// public void eraseTypes(Table aTable) {
// for (Variable symbol : symbols()) {
// Variable newSymbol = Variable.named(symbol.name(), "", aTable.containerScope());
// aTable.addSymbol(newSymbol);
// }
// }
/**
* Returns whether any of the symbols resolve to elementary type.
*
* @return whether any of the symbols resolve to elementary type.
*/
public boolean hasElementaryNames() {
for (Variable symbol : symbols()) {
String typeName = symbol.type();
if (Primitive.isElementaryType(typeName)) {
return true;
}
Typified typeFace = Library.findFace(typeName);
if (typeFace != null && Primitive.isElementaryType(typeFace.fullName())) {
return true;
}
}
return false;
}
}