/* This file is part of jpcsp. Jpcsp is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Jpcsp is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Jpcsp. If not, see <http://www.gnu.org/licenses/>. */ package jpcsp.format.rco.vsmx.interpreter; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; public class VSMXObject extends VSMXBaseObject { protected final Map<String, VSMXBaseObject> properties; private String className; private final List<String> sortedPropertyNames; public VSMXObject(VSMXInterpreter interpreter, String className) { super(interpreter); this.className = className; properties = new HashMap<String, VSMXBaseObject>(); sortedPropertyNames = new LinkedList<String>(); } private void addProperty(String name, VSMXBaseObject value) { properties.put(name, value); sortedPropertyNames.add(name); } protected static int getIndex(String name) { int index; try { index = Integer.parseInt(name); } catch (NumberFormatException e) { index = -1; } return index; } @Override public VSMXBaseObject getPropertyValue(String name) { if (lengthName.equals(name)) { return new VSMXNumber(interpreter, properties.size()); } if (prototypeName.equals(name)) { VSMXObject prototype = getPrototype(); if (prototype != null) { return prototype; } return VSMXUndefined.singleton; } VSMXBaseObject value = properties.get(name); if (value == null) { int index = getIndex(name); if (index >= 0) { if (index < properties.size()) { value = properties.get(sortedPropertyNames.get(index)); } else { value = VSMXUndefined.singleton; } } else { VSMXObject prototype = getPrototype(); if (prototype != null && prototype.properties.containsKey(name)) { value = prototype.getPropertyValue(name); } else { value = VSMXUndefined.singleton; addProperty(name, value); } } } return value; } @Override public List<String> getPropertyNames() { return sortedPropertyNames; } @Override public void setPropertyValue(String name, VSMXBaseObject value) { if (properties.containsKey(name)) { properties.put(name, value); } else { addProperty(name, value); } } @Override public void deletePropertyValue(String name) { properties.remove(name); sortedPropertyNames.remove(name); } @Override public boolean hasPropertyValue(String name) { if (prototypeName.equals(name)) { return true; } if (properties.containsKey(name)) { return true; } VSMXObject prototype = getPrototype(); if (prototype != null) { return prototype.hasPropertyValue(name); } return false; } @Override public boolean equals(VSMXBaseObject value) { if (value instanceof VSMXObject) { // Return true if both values refer to the same object return this == value; } return false; } @Override public String typeOf() { return "object"; } @Override public String getClassName() { return className; } @Override public String getStringValue() { if (hasPropertyValue("toString")) { log.warn(String.format("getStringValue on VSMXObject should be calling existing toString: %s", getPropertyValue("toString"))); } return super.getStringValue(); } protected void toString(StringBuilder s) { String[] keys = properties.keySet().toArray(new String[0]); Arrays.sort(keys); for (String key : keys) { VSMXBaseObject value = properties.get(key); if (s.length() > 1) { s.append(",\n"); } s.append(String.format("%s=%s", key, value)); } } @Override public String toString() { StringBuilder s = new StringBuilder(); s.append("["); toString(s); s.append("]"); return s.toString(); } }