/*
* Vitry, copyright (c) Hans Hoglund 2011
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*
* See COPYING.txt for details.
*/
package vitry.runtime;
import vitry.runtime.error.*;
import vitry.runtime.util.*;
abstract class AbstractEnv<K, V> implements Env<K, V>
{
private static Env<?, ?> GLOBAL = new GlobalEnvironment();
private final Env<K, V> parent;
public AbstractEnv() {
this.parent = AbstractEnv.<K, V> empty();
}
public AbstractEnv(Env<K, V> parent) {
this.parent = parent;
}
public Env<K, V> getParent()
{
return parent;
}
public V lookup(K key) throws UndefinedError
{
Env<K, V> env = this;
try
{
while (env != null)
{
if (env.hasBinding(key))
{
return env.getBinding(key);
}
env = env.getParent();
}
} catch (UndefinedError e)
{
// Rethrow with this below
}
throw new UndefinedError(key, this);
}
public Env<K, V> assoc(K key, V val)
{
return throwUnsupported();
}
/**
* Returns an persistent, empty environment. All operations except
* hasBinding and isPersistent are unsupported.
*/
public static <K, V> Env<K, V> empty()
{
return Utils.<Env<K, V>>unsafe(GLOBAL);
}
private <T> T throwUnsupported()
{
throw new UnsupportedOperationException();
}
}
class GlobalEnvironment extends AbstractEnv<Object, Object>
{
public Env<Object, Object> define(Object key, Object val) throws BindingError
{
return throwUnsupported();
}
public Env<Object, Object> extend(Object key, Object val)
{
return throwUnsupported();
}
public Env<Object, Object> extend()
{
return throwUnsupported();
}
public boolean isPersistent()
{
return true;
}
public boolean hasBinding(Object key)
{
return false;
}
public Object getBinding(Object key)
{
throw new UndefinedError(key, this); // TODO throw something lighter
}
private <T> T throwUnsupported()
{
throw new UnsupportedOperationException();
}
}