module environment; import std.array; // undocumented?! import std.string; import lqtypes; import listtools; class EnvLookupResult { Environment env; LqType result; this(Environment env, LqType value) { this.env = env; this.result = value; } } class Environment { private Environment _parent; private LqType[string] _names; this() { } /* yes, this has to stay */ this(Environment parent) { this._parent = parent; } void bind(string name, LqType value) { _names[name] = value; } EnvLookupResult lookup(string name) { LqType value; try { value = _names[name]; } catch (ArrayBoundsError e) { if (_parent is null) throw new Exception(format("name not found: %s", name)); else return _parent.lookup(name); } return new EnvLookupResult(this, value); } LqType lookup_local(string name) { LqType value; try { value = _names[name]; } catch (ArrayBoundsError e) { throw new Exception(format("name not found: %s", name)); } return value; } void rebind(string name, LqType value) { EnvLookupResult result = lookup(name); Environment env = result.env; env.bind(name, value); } Environment find_toplevel_env() { if (_parent is null) { return _parent.find_toplevel_env(); } else { return this; } } string[] get_local_names() { return _names.keys.sort; /* sorted to make the order deterministic */ } string[] get_all_names() { string[] a = get_local_names(); if (_parent !is null) { a ~= _parent.get_all_names(); } return listtools.unique(a).sort; /* sorted to make the order deterministic */ } void delete_name(string name) { EnvLookupResult elr = this.lookup(name); /* may raise error */ elr.env.delete_local(name); } void delete_local(string name) { this._names.remove(name); /* may raise error if not exist? */ } Environment parent() { return this._parent; } /* may be null */ }