package scotch.compiler.syntax.scope;
import static me.qmx.jitescript.util.CodegenUtils.sig;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import scotch.compiler.syntax.definition.Import;
import scotch.compiler.syntax.pattern.PatternCase;
import scotch.compiler.syntax.reference.ClassReference;
import scotch.compiler.syntax.reference.ModuleReference;
import scotch.compiler.syntax.reference.ValueReference;
import scotch.runtime.Callable;
import scotch.symbol.MethodSignature;
import scotch.symbol.Operator;
import scotch.symbol.Symbol;
import scotch.symbol.SymbolEntry;
import scotch.symbol.SymbolResolver;
import scotch.symbol.descriptor.DataConstructorDescriptor;
import scotch.symbol.descriptor.DataTypeDescriptor;
import scotch.symbol.descriptor.TypeClassDescriptor;
import scotch.symbol.descriptor.TypeInstanceDescriptor;
import scotch.compiler.syntax.type.Type;
import scotch.compiler.syntax.type.TypeScope;
import scotch.compiler.syntax.type.VariableType;
import scotch.compiler.syntax.util.SymbolGenerator;
public abstract class Scope implements TypeScope {
public static RootScope scope(SymbolGenerator symbolGenerator, SymbolResolver resolver) {
return new RootScope(symbolGenerator, resolver);
}
public static ModuleScope scope(Scope parent, TypeScope types, SymbolResolver resolver, SymbolGenerator symbolGenerator, String moduleName, List<Import> imports) {
return new ModuleScope(parent, types, resolver, symbolGenerator, moduleName);
}
public static ChildScope scope(Scope parent, TypeScope types, SymbolResolver resolver, SymbolGenerator symbolGenerator, String moduleName) {
return new ChildScope(parent, types, resolver, symbolGenerator, moduleName);
}
protected static boolean isConstructor_(Collection<SymbolEntry> entries, Symbol symbol) {
return entries.stream()
.filter(entry -> entry.getConstructor(symbol).isPresent())
.findFirst()
.isPresent();
}
Scope() {
// intentionally empty
}
public abstract void addDependency(Symbol symbol);
public void addLocal(String argument) {
throw new IllegalStateException();
}
public abstract void addPattern(Symbol symbol, PatternCase pattern);
public void capture(String argument) {
throw new IllegalStateException();
}
public abstract void defineDataConstructor(Symbol symbol, DataConstructorDescriptor descriptor);
public abstract void defineDataType(Symbol symbol, DataTypeDescriptor descriptor);
public abstract void defineOperator(Symbol symbol, Operator operator);
public abstract void defineSignature(Symbol symbol, Type type);
public abstract void defineValue(Symbol symbol, Type type);
public Scope enterScope() {
throw new IllegalStateException();
}
public Scope enterScope(List<Import> imports) {
throw new IllegalStateException();
}
public Scope enterScope(String moduleName) {
throw new IllegalStateException();
}
public List<String> getCaptures() {
throw new IllegalStateException();
}
public Optional<DataConstructorDescriptor> getDataConstructor(Symbol symbol) {
return getEntry(symbol).flatMap(SymbolEntry::getDataConstructor);
}
public Optional<DataTypeDescriptor> getDataType(Symbol symbol) {
return getEntry(symbol).flatMap(SymbolEntry::getDataType);
}
public abstract Set<Symbol> getDependencies();
public List<String> getLocals() {
throw new IllegalStateException();
}
public abstract Optional<TypeClassDescriptor> getMemberOf(ValueReference valueRef);
public abstract Optional<Operator> getOperator(Symbol symbol);
public abstract Scope getParent();
public abstract Map<Symbol, List<PatternCase>> getPatternCases();
public Optional<Type> getRawValue(ValueReference reference) {
return getRawValue(reference.getSymbol());
}
public abstract Optional<Type> getRawValue(Symbol symbol);
public Optional<SymbolEntry> getSiblingEntry(Symbol symbol) {
throw new IllegalStateException();
}
public abstract Optional<Type> getSignature(Symbol symbol);
public abstract Optional<TypeClassDescriptor> getTypeClass(ClassReference classRef);
public Optional<TypeInstanceDescriptor> getTypeInstance(ClassReference classReference, ModuleReference moduleReference, List<? extends Type> parameters) {
return getTypeInstances(classReference.getSymbol(), parameters).stream()
.filter(instance -> moduleReference.is(instance.getModuleName()))
.findFirst();
}
public abstract Set<TypeInstanceDescriptor> getTypeInstances(Symbol typeClass, List<? extends Type> parameters);
public Optional<Type> getValue(ValueReference reference) {
return getValue(reference.getSymbol());
}
public Optional<Type> getValue(Symbol symbol) {
return getRawValue(symbol).map(type -> type.genericCopy(this));
}
public abstract Optional<MethodSignature> getValueSignature(Symbol symbol);
public void insertChild(Scope scope) {
throw new IllegalStateException();
}
public abstract boolean isDefined(Symbol symbol);
public boolean isMember(Symbol symbol) {
return getEntry(symbol).map(SymbolEntry::isMember).orElse(false);
}
public boolean isOperator(Symbol symbol) {
return qualify(symbol).map(this::isOperator_).orElse(false);
}
public abstract Scope leaveScope();
public void prependLocals(List<String> locals) {
throw new IllegalStateException();
}
public abstract Optional<Symbol> qualify(Symbol symbol);
public abstract Symbol qualifyCurrent(Symbol symbol);
public void redefineDataConstructor(Symbol symbol, DataConstructorDescriptor descriptor) {
Optional<SymbolEntry> optionalEntry = getEntry(symbol);
if (optionalEntry.isPresent()) {
optionalEntry.get().redefineDataConstructor(descriptor);
} else {
throw new IllegalStateException("Can't redefine non-existent data constructor " + symbol.quote());
}
}
public void redefineDataType(Symbol symbol, DataTypeDescriptor descriptor) {
Optional<SymbolEntry> optionalEntry = getEntry(symbol);
if (optionalEntry.isPresent()) {
optionalEntry.get().redefineDataType(descriptor);
} else {
throw new IllegalStateException("Can't redefine non-existent data constructor " + symbol.quote());
}
}
public void redefineSignature(Symbol symbol, Type type) {
Optional<SymbolEntry> optionalEntry = getEntry(symbol);
if (optionalEntry.isPresent()) {
optionalEntry.get().redefineSignature(type.toDescriptor());
} else {
throw new IllegalStateException("Can't redefine non-existent value " + symbol.quote());
}
}
public void redefineValue(Symbol symbol, Type type) {
Optional<SymbolEntry> optionalEntry = getEntry(symbol);
if (optionalEntry.isPresent()) {
optionalEntry.get().redefineValue(type.toDescriptor(), computeValueMethod(symbol, type));
} else {
throw new IllegalStateException("Can't redefine non-existent value " + symbol.quote());
}
}
public abstract Symbol reserveSymbol();
public Symbol reserveSymbol(List<String> nestings) {
return reserveSymbol().nest(nestings);
}
public VariableType reserveType() {
return getParent().reserveType();
}
public void setParent(Scope scope) {
throw new IllegalStateException();
}
protected MethodSignature computeValueMethod(Symbol symbol, Type type) {
return MethodSignature.staticMethod(
symbol.qualifyWith(getModuleName()).getModuleClass(),
symbol.getMethodName(),
sig(Callable.class)
);
}
protected abstract Optional<SymbolEntry> getEntry(Symbol symbol);
protected abstract String getModuleName();
protected abstract boolean isDataConstructor(Symbol symbol);
protected abstract boolean isDefinedLocally(Symbol symbol);
protected boolean isExternal(Symbol symbol) {
return getParent().isExternal(symbol);
}
protected abstract boolean isOperator_(Symbol symbol);
}