package st.gravel.support.jvm;
import java.util.HashSet;
import st.gravel.core.Symbol;
import st.gravel.support.compiler.ast.AbstractClassMapping;
import st.gravel.support.compiler.ast.ClassDescriptionNode;
import st.gravel.support.compiler.ast.ClassMapping;
import st.gravel.support.compiler.ast.ClassNode;
import st.gravel.support.compiler.ast.MethodNode;
import st.gravel.support.compiler.ast.PackageNode;
import st.gravel.support.compiler.ast.Parser;
import st.gravel.support.compiler.ast.Reference;
import st.gravel.support.compiler.ast.SystemDefinitionNode;
import st.gravel.support.jvm.runtime.ImageBootstrapper;
public abstract class ClassDescriptionMirror {
public static ClassDescriptionMirror forReference(Reference reference) {
return reference.isMeta() ? new MetaclassMirror(reference)
: new ClassMirror(reference);
}
protected final Reference reference;
protected ClassDescriptionMirror(Reference reference) {
super();
this.reference = reference;
}
public Object compile_classified_(String source, String protocol) {
final MethodNode method = Parser.factory.parseMethod_(source)
.withProtocol_(protocol);
ClassDescriptionNode currentClassNode = definitionClassNode();
final MethodNode current = currentClassNode.methodOrNilAt_(method
.selector());
Symbol targetPackageName = current == null ? definitionClassNode()
.packageName() : current.packageName();
if (targetPackageName == null) {
targetPackageName = definitionClassNode().packageName();
if (targetPackageName == null) {
targetPackageName = current.packageName();
}
}
SystemDefinitionNode newSystem = ImageBootstrapper.systemMapping
.systemDefinitionNode().copyUpdatePackage_do_(
targetPackageName,
new Block1<PackageNode, PackageNode>() {
@Override
public PackageNode value_(PackageNode packageNode) {
return packageNode.copyUpdateClassNode_do_(
definitionClassNode().reference(),
new Block1<ClassNode, ClassNode>() {
@Override
public ClassNode value_(
ClassNode classNode) {
return current == null ? classNode
.withMethodNode_(method)
: classNode
.copyReplaceMethodNode_(method);
}
});
}
});
ImageBootstrapper.systemMapping.updateTo_(newSystem);
return getMethodMirror(Symbol.value(method.selector()));
}
public abstract ClassDescriptionNode definitionClassNode();
public ClassDescriptionNode runtimeClassNode() {
return ImageBootstrapper.systemMapping.classMappingAtReference_(
reference).classNode();
}
public HashSet<Symbol> definitionSelectors() {
final HashSet<Symbol> set = new HashSet<Symbol>();
definitionClassNode().selectorsDo_(new Block1<Object, String>() {
@Override
public Object value_(String selectorString) {
set.add(Symbol.value(selectorString));
return null;
}
});
return set;
}
public HashSet<Symbol> flattenedSelectors() {
final HashSet<Symbol> set = new HashSet<Symbol>();
runtimeClassNode().selectorsDo_(new Block1<Object, String>() {
@Override
public Object value_(String selectorString) {
set.add(Symbol.value(selectorString));
return null;
}
});
return set;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ClassDescriptionMirror other = (ClassDescriptionMirror) obj;
if (reference == null) {
if (other.reference != null)
return false;
} else if (!reference.equals(other.reference))
return false;
return true;
}
public MethodMirror getMethodMirror(Object selObject) {
if (!(selObject instanceof Symbol))
return null;
Symbol selector = (Symbol) selObject;
MethodNode method = getMethodNode(selector);
if (method == null) {
return null;
}
return new MethodMirror(method, this);
}
private MethodNode getMethodNode(Symbol selector) {
MethodNode method = runtimeClassNode().methodOrNilAt_(
selector.asString());
return method;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((reference == null) ? 0 : reference.hashCode());
return result;
}
public boolean includesBehavior_(Object classOrMirror) {
if (classOrMirror instanceof ClassDescriptionMirror)
return ObjectExtensions.includesBehavior_(instance(),
((ClassDescriptionMirror) classOrMirror).instance());
return ObjectExtensions.includesBehavior_(instance(), classOrMirror);
}
public ObjectClass instance() {
Object singleton = ImageBootstrapper.systemMapping
.singletonAtReference_(reference.nonmeta());
return (ObjectClass) singleton;
}
public Symbol packageName() {
return definitionClassNode().packageName();
}
public boolean isTrait() {
return definitionClassNode().isTrait();
}
public Reference reference() {
return reference;
}
public HashSet<ClassDescriptionMirror> subclasses() {
final HashSet<ClassDescriptionMirror> set = new HashSet<>();
ImageBootstrapper.systemMapping.subclassMappingsFor_do_(reference,
new Block1<Object, AbstractClassMapping>() {
@Override
public Object value_(AbstractClassMapping arg1) {
set.add(ClassDescriptionMirror.forReference(arg1
.reference()));
return null;
}
});
return set;
}
public ClassDescriptionMirror superclass() {
Reference superclassReference = ImageBootstrapper.systemMapping
.classMappingAtReference_(reference).superclassReference();
if (superclassReference == null)
return null;
return ClassDescriptionMirror.forReference(superclassReference);
}
public boolean canUnderstand_(Symbol selector) {
return getMethodNode(selector) != null;
}
}