package org.dynjs.runtime; import java.util.HashMap; import java.util.Map; import org.dynjs.exception.ThrowException; public class DeclarativeEnvironmentRecord implements EnvironmentRecord { private Map<String, PropertyDescriptor> mutableBindings = new HashMap<String, PropertyDescriptor>(); private Map<String, PropertyDescriptor> immutableBindings = new HashMap<String, PropertyDescriptor>(); @Override public boolean hasBinding(ExecutionContext context, String name) { return this.mutableBindings.containsKey(name) || this.immutableBindings.containsKey(name); } @Override public void createMutableBinding(ExecutionContext context, final String name, final boolean configurable) { // 10.2.1.1.2 if (hasBinding(context, name)) { throw new AssertionError("10.2.1.1.2: Binding already exists for " + name); } PropertyDescriptor desc = new PropertyDescriptor(); desc.setValue(Types.UNDEFINED); desc.setConfigurable(configurable); this.mutableBindings.put(name, desc); } public void createMutableBinding(final String name, final boolean configurable) { DeclarativeEnvironmentRecord.this.createMutableBinding(null, name,configurable); } @Override public void setMutableBinding(ExecutionContext context, String name, Object value, boolean strict) { // 10.2.1.1.3 if (!hasBinding(context, name)) { throw new AssertionError("10.2.1.1.3: No binding exists for " + name); } if (this.mutableBindings.containsKey(name)) { PropertyDescriptor desc = this.mutableBindings.get(name); desc.setValue(value); return; } if (strict) { throw new ThrowException(context, context.createTypeError("attempt to change immutable binding is not allowed")); } } public void setMutableBinding(String name, Object value, boolean strict) { DeclarativeEnvironmentRecord.this.setMutableBinding(null, name, value, strict); } // FIXME: describe spec deviance public void assignMutableBinding(ExecutionContext context, String name, Object value, boolean configurable, boolean strict) { final boolean exists = hasBinding(context, name); if (!exists) { PropertyDescriptor desc = new PropertyDescriptor(); desc.setValue(value); desc.setConfigurable(configurable); this.mutableBindings.put(name, desc); } else { PropertyDescriptor desc = this.mutableBindings.get(name); desc.setValue(value); return; } } @Override public Object getBindingValue(ExecutionContext context, String name, boolean strict) { // 10.2.1.1.4 if (!hasBinding(context, name)) { throw new AssertionError("10.2.1.1.4: No binding exists for " + name); } PropertyDescriptor desc = this.immutableBindings.get(name); if (desc != null && !desc.hasInitialized()) { if (strict) { throw new ThrowException(context, context.createTypeError(name + " is not initialized")); } return Types.UNDEFINED; } if (desc != null) { return desc.getValue(); } desc = this.mutableBindings.get(name); if (desc == null) { return Types.UNDEFINED; } return desc.getValue(); } @Override public boolean deleteBinding(ExecutionContext context, String name) { // 10.2.1.1.5 PropertyDescriptor desc = this.immutableBindings.get(name); if (desc == null) { desc = this.mutableBindings.get(name); } if (desc == null) { return true; } if (!desc.isConfigurable()) { return false; } return (this.mutableBindings.remove(name) != null); } @Override public Object implicitThisValue() { // 10.2.1.1.6 return Types.UNDEFINED; } public void createImmutableBinding(final String name) { // 10.2.1.1.7 PropertyDescriptor desc = new PropertyDescriptor(); desc.setValue(Types.UNDEFINED); this.immutableBindings.put(name, desc); } public void initializeImmutableBinding(String name, Object value) { // 10.2.1.1.8 PropertyDescriptor desc = this.immutableBindings.get(name); desc.setValue(value); desc.setInitialized(true); } public boolean isGlobal() { return false; } }