Scope.java
package Hoot.Runtime.Behaviors;
import java.util.*;
import Hoot.Runtime.Values.*;
import Hoot.Runtime.Emissions.*;
import Hoot.Runtime.Faces.Resulting;
import static Hoot.Runtime.Functions.Utils.*;
/**
* A language scope, and management thereof.
*
* @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 Scope extends NamedItem implements Resulting {
public Scope(NamedItem parentItem) { super(parentItem); }
@Override public String description() { return name(); }
@Override public void clean() { super.clean(); locals().clean(); whisper("cleaned " + description()); }
private static final Stack<Scope> Scopes = new Stack<>();
private static void popSafely() { if (!Scopes.empty()) Scopes.pop(); }
public static Scope currentFile() { return Scopes.empty() ? null : Scopes.peek(); }
private void pushScope(Scope scope) {
if (scope.isFile()) {
Scopes.push(scope);
}
else {
currentFile().currentScope(scope);
}
}
public Scope popScope() {
if (this.isFile()) {
popSafely();
}
else {
currentFile().currentScope(nullOr(s -> s.containerScope(), current()));
}
return reportScope(currentScope());
}
protected void currentScope(Scope scope) { }
public Scope currentScope() { return current(); }
public Scope makeCurrent() { pushScope(this); return this; }
public static Scope current() { return nullOr(f -> f.currentScope(), currentFile()); }
private Scope reportScope(Scope scope) { if (hasAny(scope)) scope.reportScope(); return scope; }
public Scope reportScope() { whisper("scope now " + description()); return this; }
// public boolean resolves(Named reference) { return false; }
// public Scope scopeResolving(Named reference) { return containerScope().scopeResolving(reference); }
// public Class resolveType(Named reference) { return containerScope().resolveType(reference); }
// public String resolveTypeName(Named reference) { return containerScope().resolveTypeName(reference); }
protected Table locals = new Table(this);
public Table locals() { return this.locals; }
public boolean hasLocals() { return !locals().isEmpty(); }
public boolean hasLocal(String symbolName) { return locals().containsSymbol(symbolName); }
public void addLocal(Variable variable) { locals().addSymbol(variable); }
public Variable localNamed(String symbol) { return locals().symbolNamed(symbol); }
@Override public Emission emitItem() { return emitScope(); }
@Override public Emission emitOptimized() { return emitScope(); }
@Override public Emission emitPrimitive() { return emitScope(); }
public Emission emitScope() { return null; } // derived classes override this!
public List<Emission> emitLocalVariables() { return map(locals().definedSymbols(), v -> v.emitLocal()); }
} // Scope