Item.java
package Hoot.Runtime.Emissions;
import java.util.*;
import java.util.function.Predicate;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.TokenStream;
import org.antlr.v4.runtime.tree.Tree;
import Hoot.Runtime.Faces.Named;
import Hoot.Runtime.Notes.Note;
import Hoot.Runtime.Notes.NoteList;
import Hoot.Runtime.Values.Operand;
import Hoot.Runtime.Behaviors.Scope;
import Hoot.Runtime.Names.TypeName;
import Hoot.Runtime.Names.TypeName.Resolver;
import static Hoot.Runtime.Functions.Utils.*;
/**
* An item with its associated parse context and parent.
*
* @author nik <nikboyd@sonic.net>
* @see "Copyright 2010,2021 Nikolas S Boyd."
* @see "Permission is granted to copy this work provided this copyright statement is retained in all copies."
*/
public abstract class Item implements EmissionSource, Resolver {
protected Item() { super(); }
protected Item(Item container) { this(); inside(container); }
@SuppressWarnings("unchecked")
protected <T extends Item> Class<T> itemType() { return (Class<T>)getClass(); }
public final <T extends Item> T inside(Item container) { container(container); return asType(itemType()); }
public void clean() { } // derived classes sometimes override this
public void release() { // derived classes sometimes override this
if (hasOne(container())) {
// breaks cycles, if needed, to promote proper garbage collection
container().release();
this.container = null;
}
}
protected Item container;
public Item container() { return this.container; }
public void container(Item container) { this.container = container; scope(container); }
protected void contain(Item item) { if (hasOne(item)) item.container(this); }
protected <T extends Item> void containAll(List<T> items) {
if (hasAny(items)) items.forEach(item -> this.contain(item)); }
protected Scope itemScope;
public Scope scope() { return this.itemScope; }
protected void scope(Scope s) { this.itemScope = s; }
protected void scope(Item it) { if (hasOne(it)) scope(hasInstance(it) ? (Scope)it : it.containerScope()); }
public Scope containerScope() { return findParent(Scope.class); }
public static boolean hasInstance(Item item) { return Scope.class.isInstance(item); }
protected NoteList notes = new NoteList();
public NoteList notes() { return this.notes; }
public void note(Note note) { this.notes.note(note); }
public void noteAll(List<Note> notes) { notes().noteAll(notes); }
@Override public TypeName resolveTypeNamed(Named reference) {
return nullOr(s -> s.resolveTypeNamed(reference), containerScope()); }
public boolean isVoidedContext() { return false; }
public boolean hasVoidedContext() {
Scope m = methodScope();
Operand v = variableContainer();
if (hasOne(m)) return m.isVoidedContext();
if (hasOne(v)) return v.isVoidedContext();
return false;
}
public boolean hasPrimitiveContext() {
Scope m = methodScope();
Operand v = variableContainer();
if (hasOne(m)) return m.isPrimitive();
if (hasOne(v)) return v.isPrimitive();
return false;
}
protected Scope findScope(Predicate<Item> p) { return findItem(Scope.class, p); }
public Operand variableContainer() { return findItem(Operand.class, s -> s.isVariable()); }
public Scope blockScope() { return findScope(s -> s.isBlock()); }
public Scope methodScope() { return findScope(s -> s.isMethod()); }
public Scope facialScope() { return findScope(s -> s.isFacial()); }
public Scope fileScope() { return findScope(s -> s.isFile()); }
public List<Scope> blockScopes() {
Scope b = blockScope();
Scope m = methodScope();
List<Scope> results = emptyList(Scope.class);
if (hasOne(m)) { // collect all block scopes within a method
while (b != m) { results.add(b); b = b.containerScope(); }
results.add(m); // including the method scope
}
return results;
}
@Override public int nestLevel() {
int level = (hasNone(container())) ? 0 : container().nestLevel();
whisper("level " + level); return level; }
public <T extends Item> T parentItem(Class<T> itemType) { return itemType.cast(container()); }
public <T extends Item> T asType(Class<T> itemType) { return itemType.cast(this); }
public <R extends Item> R itemNotes() { return null; } // override this!
public List<String> knownTypes() { return emptyList(String.class); } // override this
public boolean isEmpty() { return false; }
public boolean missingAny(Item... items) { for (Item item : items) if (hasNone(item)) return true; return false; }
public boolean isStatic() { return notes().isStatic(); }
public boolean isAbstract() { return notes().isAbstract(); }
public boolean isStacked() { return notes().isStacked(); }
public boolean isPrimitive() { return notes().isPrimitive(); }
public boolean isFramed() { return false; }
public boolean isVariable() { return false; }
public boolean isBlock() { return false; }
public boolean isMethod() { return false; }
public boolean isFacial() { return false; }
public boolean isFile() { return false; }
protected boolean matchesExactly(Class<?> itemType) { return hasOne(itemType) && itemType.equals(getClass()); }
protected boolean matches(Class<?> itemType) { return hasOne(itemType) && itemType.isAssignableFrom(getClass()); }
/**
* @return an item of a specific kind, within limits, or null
* @param <T> an item type
* @param itemType an item type
* @param limitTypes limit types that truncate search
*/
public <T extends Item> T findItem(Class<T> itemType, Class<?>... limitTypes) {
if (hasNone(itemType)) return null;
return this.matches(itemType) ? asType(itemType) : this.findParent(itemType, limitTypes); }
protected <R extends Item> R findItem(Class<R> itemType, Predicate<Item> p) {
Item item = this; while (hasOne(item) && !p.test(item)) item = item.container();
return itemType.cast(item); }
/**
* @return whether a parent of the given kind exists
* @param <T> a parent type
* @param itemType a parent type
* @param limitTypes limit types
*/
public <T extends Item> boolean hasParent(Class<T> itemType, Class<?>... limitTypes) {
return findParent(itemType, limitTypes) != null; }
/**
* @return a parent item of a specific kind, within limits, or null
* @param <T> a parent item type
* @param itemType a parent item type
* @param limitTypes limit types that truncate search
*/
public <T extends Item> T findParent(Class<T> itemType, Class<?>... limitTypes) {
if (hasNone(itemType)) return null;
if (hasNone(container())) return null;
if (limitTypes.length > 0) {
for (Class<?> testType : limitTypes) {
if (container().matches(testType)) {
return null; // limit search scope
}
}
}
return container().findItem(itemType, limitTypes);
}
public <T extends Item> T findParentExactly(Class<T> itemType, Class<?>... limitTypes) {
if (hasNone(itemType)) return null;
if (hasNone(container())) return null;
if (limitTypes.length > 0) {
for (Class<?> testType : limitTypes) {
if (container().matchesExactly(testType)) {
return null; // limit search scope
}
}
}
return container().findExactly(itemType, limitTypes);
}
public <T extends Item> T findExactly(Class<T> itemType, Class<?>... limitTypes) {
return nullOr(it -> matchesExactly(it) ? asType(it) : findParentExactly(it, limitTypes), itemType); }
protected int sourceLine = 0;
public int sourceLine() { return sourceLine; }
public void sourceLine(int lineNumber) { sourceLine = lineNumber + 1; }
public <T extends Item> T withLine(int line) { sourceLine(line); return asType(itemType()); }
public String description() { return getClass().getName(); }
public String commentFrom(Tree node) { return nullOr(hidden -> hidden.getText(), hiddenToken((Tree) node)); }
public TokenStream tokenStream() { return null; } // dervied classes override!!
public Token tokenFrom(Tree node) { return (Token)node.getPayload(); }
public Token hiddenToken(Tree node) { return nullOr(n -> hiddenToken(tokenFrom(n)), node); }
public Token hiddenToken(Token token) {
if (hasNone(token) || hasNone(tokenStream())) return null;
Token candidate = tokenStream().get(token.getTokenIndex() - 1);
return (candidate.getChannel() == Token.HIDDEN_CHANNEL ? candidate : null);
}
protected static final String ALL = "ALL";
protected static final String Wild = "*";
protected static final String Hash = "#";
protected static final String Blank = " ";
protected static final String Quote = "\"";
protected static final String Trophe = "'";
protected static final String Arrayed = "[]";
protected static final String Etc = "...";
protected static final Emission[] EmptyArgs = {};
protected static final List<Emission> EmptyList = wrap(EmptyArgs);
} // Item