package org.perl6.metamodel;
import java.util.*;
import org.perl6.metamodel.metaclass.Dispatcher;
public class MetaClass {
/* ATTRIBUTES */
// meta-info
private String name;
private String version;
private String authority;
// the guts of the metaclass
/*
XXX - these all should likely have their own
classes, so that I don't need to do all the
casting back and forth. But they will do for now.
*/
private ArrayList MRO;
private ArrayList superclasses = new ArrayList();
private HashMap instance_methods = new HashMap();
private HashMap instance_attributes = new HashMap();
private HashMap class_methods = new HashMap();
private HashMap class_attributes = new HashMap();
/* METHODS */
// constructors
public MetaClass (String _name) {
this(_name, "0.0.0");
}
public MetaClass (String _name, String _version) {
name = _name;
version = _version;
}
public MetaClass (String _name, String _version, String _authority) {
this(_name, _version);
authority = _authority;
}
// meta info accessor/mutators
public String name () {
return name;
}
public void name (String _name) {
name = _name;
}
public String version () {
return version;
}
public void version (String _version) {
version = _version;
}
public String authority () {
return authority;
}
public void authority (String _authority) {
authority = _authority;
}
public String identifier () {
String ident = name + "-" + version;
if (authority != null) {
ident += "-" + authority;
}
return ident;
}
// superclasses
public void superclasses (ArrayList _superclasses) {
superclasses = _superclasses;
}
public ArrayList superclasses () {
return superclasses;
}
public boolean is_a (String classname) {
if (name == classname) return true;
for (int i = 0; i < superclasses.size(); i++) {
if (((MetaClass) superclasses.get(i)).is_a(classname)) return true;
}
return false;
}
// MRO
public Dispatcher dispatcher (String mro) {
return new Dispatcher(this, mro);
}
public Dispatcher dispatcher () {
return new Dispatcher(this, ":canonical");
}
public ArrayList _remove_empty_seqs (ArrayList seqs) {
ArrayList nonemptyseqs = new ArrayList();
for (int i = 0; i < seqs.size(); i++) {
if (((ArrayList) seqs.get(i)).size() != 0) {
nonemptyseqs.add(seqs.get(i));
}
}
return nonemptyseqs;
}
public boolean _in_tail (ArrayList seq, MetaClass cand) {
if (seq.indexOf(cand) > 0) return true;
return false;
}
public void _remove_heads_if (MetaClass cand, ArrayList nonemptyseqs) {
for (int i = 0; i < nonemptyseqs.size(); i++) {
ArrayList current = (ArrayList) nonemptyseqs.get(i);
if (!current.isEmpty() && current.get(0) == cand) {
current.remove(0);
}
}
}
public ArrayList merge (ArrayList seqs) throws Exception {
ArrayList res = new ArrayList();
while (true) {
// remove all empty seqences
ArrayList nonemptyseqs = _remove_empty_seqs(seqs);
// return the list if we have no more no-empty sequences
if (nonemptyseqs.size() == 0) {
return res;
}
MetaClass cand = null;
for (int i = 0; i < nonemptyseqs.size(); i++) {
ArrayList seq = (ArrayList) nonemptyseqs.get(i);
cand = (MetaClass) seq.get(0);
boolean nothead = false;
for (int j = 0; j < nonemptyseqs.size(); j++) {
ArrayList sub_seq = (ArrayList) nonemptyseqs.get(j);
if (_in_tail(sub_seq, cand)) {
nothead = true;
break;
}
}
if (nothead == false) {
// leave the loop with our candidate ...
break;
}
else {
// otherwise, reject it ...
cand = null;
}
}
if (cand == null) {
throw new Exception("Inconsistent hierarchy");
}
res.add(cand);
// now loop through our non-empties and pop
// off the head if it matches our candidate
_remove_heads_if(cand, seqs);
}
}
public ArrayList MRO () throws Exception {
if (MRO == null) {
ArrayList args = new ArrayList();
ArrayList _this = new ArrayList();
_this.add(this);
args.add(_this);
for (int i = 0; i < superclasses.size(); i++) {
args.add(((MetaClass) superclasses.get(i)).MRO());
}
args.add(superclasses);
MRO = merge(args);
}
return MRO;
}
// Attributes
public void add_attribute (String label, Attribute attribute, String which_table) throws Exception {
if (which_table.equals("INSTANCE")) {
instance_attributes.put(label, attribute);
}
else if (which_table.equals("CLASS")) {
class_attributes.put(label, attribute);
}
else {
throw new Exception ("add_attribute: Unsupported attribute table");
}
}
public void add_attribute (String label, Attribute attribute ) {
instance_attributes.put(label, attribute);
}
public boolean has_attribute (String label, String which_table) throws Exception {
if (which_table.equals("INSTANCE")) {
return instance_attributes.containsKey(label);
}
else if (which_table.equals("CLASS")) {
return class_attributes.containsKey(label);
}
else {
throw new Exception ("has_attribute: Unsupported attribute table");
}
}
public boolean has_attribute (String label) {
return instance_attributes.containsKey(label);
}
public Attribute get_attribute (String label, String which_table) throws Exception {
if (which_table.equals("INSTANCE")) {
return (Attribute) instance_attributes.get(label);
}
else if (which_table.equals("CLASS")) {
return (Attribute) class_attributes.get(label);
}
else
{
throw new Exception("get_attribute: Unsupported attribute table");
}
}
public Attribute get_attribute (String label) {
return (Attribute) instance_attributes.get(label);
}
// Methods
public void add_method (String label, Method method, String which_table) throws Exception {
if (which_table.equals("INSTANCE")) {
instance_methods.put(label, method);
}
else if (which_table.equals("CLASS")) {
class_methods.put(label, method);
}
else {
throw new Exception ("Unsupported dispatch table");
}
}
public void add_method (String label, Method method) {
instance_methods.put(label, method);
}
public boolean has_method (String label, String which_table) throws Exception {
if (which_table.equals("INSTANCE")) {
return instance_methods.containsKey(label);
}
else if (which_table.equals("CLASS")) {
return class_methods.containsKey(label);
}
else {
throw new Exception ("Unsupported dispatch table");
}
}
public boolean has_method (String label) {
return instance_methods.containsKey(label);
}
public Method get_method (String label, String which_table) throws Exception {
if (which_table.equals("INSTANCE")) {
return (Method) instance_methods.get(label);
}
else if (which_table.equals("CLASS")) {
return (Method) class_methods.get(label);
}
else {
throw new Exception ("Unsupported dispatch table");
}
}
public Method get_method (String label) {
return (Method) instance_methods.get(label);
}
}