/**
* Copyright (c) 2009-2011, The HATS Consortium. All rights reserved.
* This file is licensed under the terms of the Modified BSD License.
*/
package abs.backend.java.lib.runtime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import abs.backend.java.codegeneration.dynamic.DynamicException;
import abs.backend.java.lib.types.ABSBool;
import abs.backend.java.lib.types.ABSClass;
import abs.backend.java.lib.types.ABSValue;
import abs.backend.java.observing.manipulation.ClassManipulator;
public class ABSDynamicClass implements ABSClass {
private String name;
private Map<String, ABSField> fields = new HashMap<String, ABSField>();
private Map<String, ABSClosure> methods = new HashMap<String,ABSClosure>();
private ABSClosure constructor;
private List<String> params;
private ABSDynamicClass nextVersion;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void addField(String fName, ABSField f) throws DynamicException {
if (! fields.containsKey(fName))
fields.put(fName,f);
else
throw new DynamicException("Field " + fName + " already defined for class " + name + ".");
}
public void removeField(String fName) throws DynamicException {
if (fields.containsKey(fName))
fields.remove(fName);
else
throw new DynamicException("Field " + fName + " not defined for class " + name + ".");
}
public ABSField getField(String fName) throws DynamicException {
if (fields.containsKey(fName))
return fields.get(fName);
else
throw new DynamicException("Field " + fName + " not defined for class " + name + ".");
}
public boolean hasMethod(String mName) {
return methods.containsKey(mName);
}
public void addMethod(String mName, ABSClosure m) throws DynamicException {
if (! hasMethod(mName))
methods.put(mName, m);
else
throw new DynamicException("Method " + mName + " already defined for class " + name + ".");
}
public void removeMethod(String mName) throws DynamicException {
if (hasMethod(mName))
methods.remove(mName);
else
throw new DynamicException("Method " + mName + " not defined for class " + name + ".");
}
public ABSClosure getMethod(String mName) throws DynamicException {
if (hasMethod(mName))
return methods.get(mName);
else
throw new DynamicException("Method " + mName + " not defined for class " + name + ".");
}
public void setConstructor(ABSClosure constructor) {
this.constructor = constructor;
}
public ABSClosure getConstructor() {
return constructor;
}
public Set<String> getFieldNames() {
return fields.keySet();
}
public Set<String> getMethodNames() {
return methods.keySet();
}
public void setParams(String... args) {
setParams(Arrays.asList(args));
}
public void setParams(List<String> params) {
this.params = params;
}
public List<String> getParams() {
if (params == null) {
return Collections.emptyList();
}
return params;
}
// Create the "next version" of this class, which can be updated independently
public ABSDynamicClass createNextVersion() {
ABSDynamicClass copy = new ABSDynamicClass();
copy.name = name;
for (String f : fields.keySet())
copy.fields.put(f, fields.get(f));
for (String m : methods.keySet())
copy.methods.put(m, methods.get(m));
copy.params = params;
copy.constructor = constructor;
copy.nextVersion = null;
nextVersion = copy;
return copy;
}
public ABSDynamicClass getNextVersion() {
return nextVersion;
}
private View __view;
public synchronized ClassManipulator getView() {
if (__view == null) {
__view = new View();
}
return __view;
}
private class View implements ClassManipulator {
@Override
public String getName() {
return ABSDynamicClass.this.getName();
}
@Override
public List<String> getFieldNames() {
return new ArrayList<String>(ABSDynamicClass.this.getFieldNames());
}
@Override
public List<String> getMethodNames() {
if (methods == null) return Collections.emptyList();
return new ArrayList<String>(methods.keySet());
}
@Override
public void addField(String name, String type, ABSClosure init) {
// FIXME
if (fields == null) {
fields = new HashMap<String,ABSField>();
}
fields.put(name, new ABSField());
}
}
@Override
public ABSBool eq(ABSValue o) {
if (o instanceof ABSDynamicClass)
return ABSBool.fromBoolean(name.equals(((ABSDynamicClass)o).getName()));
else
return ABSBool.FALSE;
}
@Override
public ABSBool notEq(ABSValue o) {
return eq(o).negate();
}
@Override
public ABSBool gt(ABSValue other) {
if (other.getClass() == ABSDynamicClass.class) {
return ABSBool.fromBoolean(this.name.compareTo(((ABSDynamicClass)other).getName()) > 0);
} else {
// type error, not reached
return ABSBool.FALSE;
}
}
@Override
public ABSBool lt(ABSValue other) {
if (other.getClass() == ABSDynamicClass.class) {
return ABSBool.fromBoolean(this.name.compareTo(((ABSDynamicClass)other).getName()) < 0);
} else {
// type error, not reached
return ABSBool.FALSE;
}
}
@Override
public ABSBool gtEq(ABSValue other) {
if (other.getClass() == ABSDynamicClass.class) {
return eq(other).or(gt(other));
} else {
// type error, not reached
return ABSBool.FALSE;
}
}
@Override
public ABSBool ltEq(ABSValue other) {
if (other.getClass() == ABSDynamicClass.class) {
return eq(other).or(lt(other));
} else {
// type error, not reached
return ABSBool.FALSE;
}
}
@Override
public boolean isDataType() {
return false;
}
@Override
public boolean isReference() {
return true;
}
}