annotate src/samer/core_/Environment.java @ 8:5e3cbbf173aa tip

Reorganise some more
author samer
date Fri, 05 Apr 2019 22:41:58 +0100
parents bf79fb79ee13
children
rev   line source
samer@0 1 /*
samer@0 2 * Environment.java
samer@0 3 *
samer@0 4 * Copyright (c) 2001, Samer Abdallah, King's College London.
samer@0 5 * All rights reserved.
samer@0 6 *
samer@0 7 * This software is provided AS IS and WITHOUT ANY WARRANTY;
samer@0 8 * without even the implied warranty of MERCHANTABILITY or
samer@0 9 * FITNESS FOR A PARTICULAR PURPOSE.
samer@0 10 */
samer@0 11
samer@0 12 package samer.core;
samer@0 13
samer@0 14 /**
samer@0 15 An Environment is a way of managing named values.
samer@0 16 The names form a heirarchical system using dot (.) as
samer@0 17 a seperator. (See Node class)
samer@0 18
samer@0 19 Each Environment has a parent Environment, except for the
samer@0 20 singleton top level Environment.
samer@0 21
samer@0 22 Each Environment has a Node which serves as a 'current
samer@0 23 directory'. Environments form a chain: if one
samer@0 24 Environment cannot satisfy a request for a named
samer@0 25 binding, it should ask its parent.
samer@0 26
samer@0 27 @see samer.core.Node
samer@0 28 @see samer.core.X
samer@0 29 */
samer@0 30
samer@0 31 public class Environment
samer@0 32 {
samer@0 33 protected Environment parent;
samer@0 34 protected Node base;
samer@0 35
samer@0 36 /** Construct a new Environment with the given parent
samer@0 37 and base node */
samer@0 38 public Environment(Environment parent, Node base) { this.parent=parent; this.base=base; }
samer@0 39
samer@0 40 /** Construct a new Environment with the given parent
samer@0 41 and a base node relative to the parent Environment.
samer@0 42 That is, <code>node = new Node(name, parent.node());</code>
samer@0 43 */
samer@0 44 public Environment(Environment parent, String name) {
samer@0 45 this(parent,new Node(name,parent.base));
samer@0 46 }
samer@0 47
samer@0 48 /** Return this environment's parent, or null of top level */
samer@0 49 public final Environment parent() { return parent; }
samer@0 50
samer@0 51 /** Return this environment's associated node */
samer@0 52 public final Node node() { return base; }
samer@0 53
samer@0 54 /*
samer@0 55 * these methods form the main implementation of the Environment and
samer@0 56 * are meant to be overridden by subclasses.
samer@0 57 */
samer@0 58
samer@0 59 /** Add and return a new named binding */
samer@0 60 public Binding add(String nm, Object o) { return parent.add(abs(nm),o); }
samer@0 61
samer@0 62 /** Add anonymous datum */
samer@0 63 public void add(Object obj) { parent.add(obj); }
samer@0 64
samer@0 65 public void store(String nm, Autocoder o) { parent.store(abs(nm),o); }
samer@0 66 public void store(String nm, Object o, Codec c) { parent.store(abs(nm),o,c); }
samer@0 67
samer@0 68 /** Return next anonymous datum */
samer@0 69 public Datum datum() { return parent.datum(); }
samer@0 70
samer@0 71 /** Return Datum that best matches given name */
samer@0 72 public Datum datum(String name) { return parent.datum(abs(name)); }
samer@0 73
samer@0 74 /** Return Binding that best matches given name */
samer@0 75 public Binding binding(String name) { return parent.binding(abs(name)); }
samer@0 76
samer@0 77 /** Return an Iterator that will step through all data in this
samer@0 78 Environment and it's ancestors */
samer@0 79 public Iterator data() { return parent.data(); }
samer@0 80
samer@0 81 // ... Interfaces ....................................................
samer@0 82
samer@0 83 /**
samer@0 84 Basic interface for getting at a particular stored object or
samer@0 85 value.
samer@0 86 There is no concept of returning the value as-is: it must
samer@0 87 be translated in to an object of some desired class.
samer@0 88 Value can be extracted in one of two ways:
samer@0 89 a Codec, which is an object which knows how to convert
samer@0 90 between stored data and some desired class of object.
samer@0 91 The other way is via an Autocoder, which is basically
samer@0 92 an object with it's own Codec built in.
samer@0 93 */
samer@0 94
samer@0 95 public interface Datum {
samer@0 96
samer@0 97 /** the stored name of this Datum */
samer@0 98 String name();
samer@0 99
samer@0 100 /** goodness of name matching procedure used to find this Datum */
samer@0 101 int score();
samer@0 102
samer@0 103 // Object get() throws Exception; // return intrinsic class ??
samer@0 104 // Object get(Codec c) throws Exception; // no default supplied
samer@0 105
samer@0 106 /** return object as decoded by Codec c. If this Datum is a
samer@0 107 null Datum, ie contains no data, return def */
samer@0 108 Object get(Codec c, Object def); // ?? copy semantics? exception?
samer@0 109
samer@0 110 /** decode value in to Autocoder obj */
samer@0 111 void get(Autocoder obj) throws Exception;
samer@0 112
samer@0 113 }
samer@0 114
samer@0 115 /**
samer@0 116 A Binding is a Datum in which the value is an accessible Object,
samer@0 117 ie one that doesn't need decoding. Unlike a Datum, this value
samer@0 118 can be set or removed from the Environment.
samer@0 119 */
samer@0 120 public interface Binding extends Datum {
samer@0 121 Object get() throws Exception;
samer@0 122 void set(Object obj);
samer@0 123 void remove();
samer@0 124 }
samer@0 125
samer@0 126 /**
samer@0 127 A null Binding that has no data.
samer@0 128 All attempts to read value throw an Exception, except get()
samer@0 129 with a default supplied.
samer@0 130 */
samer@0 131 public final static Binding Null = new Binding() {
samer@0 132 public String name() { return "null"; }
samer@0 133 public int score() { return 1000000000; } // Mr. Billion
samer@0 134
samer@0 135 public Object get() throws Exception { throw new Exception(); }
samer@0 136 public Object get(Codec c, Object def) { return def==null ? def : c.decode(def); } // ??
samer@0 137 // public void get(Autocoder obj) throws Exception { throw new Exception(); }
samer@0 138 public void get(Autocoder obj) {}
samer@0 139
samer@0 140 public void set(Object obj) { throw new RuntimeException(); }
samer@0 141 public void remove() { throw new RuntimeException(); }
samer@0 142 };
samer@0 143
samer@0 144 /** This is an object which knows how to code and decode itself. */
samer@0 145 public interface Autocoder
samer@0 146 {
samer@0 147 /** return this object as a string */
samer@0 148 String string(); // as string
samer@0 149
samer@0 150 /** return this object as any object of a convenient class.
samer@0 151 Strictly speaking, should return an <i>immutable</i>
samer@0 152 representation of the object.
samer@0 153 */
samer@0 154 Object object();
samer@0 155
samer@0 156 /** set this object by decoding supplied object, which may be
samer@0 157 a string. This method can be as smart as you like, behaving
samer@0 158 differently for different classes of supplied object.
samer@0 159 */
samer@0 160 void decode(Object o);
samer@0 161 }
samer@0 162
samer@0 163 /** This is an object which knows how to code and decode on behalf
samer@0 164 of some other class which represents the actual data. */
samer@0 165 public interface Codec {
samer@0 166 /** return Class of object that this Codec deals with */
samer@0 167 Class targetClass();
samer@0 168
samer@0 169 // methods for encoding object for storage
samer@0 170 String string(Object o); // convert object to string
samer@0 171 Object object(Object o); // convert object to another object
samer@0 172 Object decode(Object o); // convert other object to target class
samer@0 173 }
samer@0 174
samer@0 175 /** For iterating through data in environment,
samer@0 176 returning a Datum for each item
samer@0 177 */
samer@0 178 public interface Iterator {
samer@0 179 boolean hasNext();
samer@0 180 Datum next();
samer@0 181 }
samer@0 182
samer@0 183 /** Steps through two iterators consecutively */
samer@0 184 protected static class CompoundIterator implements Iterator {
samer@0 185 Iterator i1, i2;
samer@0 186 public CompoundIterator(Iterator a, Iterator b) { i1=a; i2=b; }
samer@0 187 public boolean hasNext() {
samer@0 188 if (i1.hasNext()) return true;
samer@0 189 if (i2==null) return false;
samer@0 190 i1=i2; i2=null; return i1.hasNext();
samer@0 191 }
samer@0 192 public Datum next() {
samer@0 193 if (i1.hasNext()) return i1.next();
samer@0 194 i1=i2; i2=null; return i1.next();
samer@0 195 }
samer@0 196 }
samer@0 197
samer@0 198 // ...................................................................
samer@0 199
samer@0 200 /** Return absolute node path for given name. If name begins
samer@0 201 with '.', then it is already an absolute name. Otherwise, the
samer@0 202 base node for this Environment is prepended.
samer@0 203 */
samer@0 204 public final String abs(String name) {
samer@0 205 return Node.isAbsolute(name) ? name : base.fullNameFor(name);
samer@0 206 }
samer@0 207
samer@0 208 /** Return node name relative to this Environment's node.
samer@0 209 Throws an Exception if the supplied name is absolute and
samer@0 210 NOT a child of this Environment's node.
samer@0 211 */
samer@0 212 public final String rel(String name) {
samer@0 213 if (!Node.isAbsolute(name)) return name;
samer@0 214 String fullbase=base.fullName();
samer@0 215 if (!name.startsWith(fullbase)) throw new Error("nonlocal node name:" + name);
samer@0 216 return name.substring(fullbase.length()+1); // miss out dot!
samer@0 217 }
samer@0 218
samer@0 219 /** Returns true if the given name is a subnode of this environment's node,
samer@0 220 ie, if it can belong in this environment
samer@0 221 */
samer@0 222 protected boolean belongs(String name) { return base.isSubnode(name); }
samer@0 223
samer@0 224 /** Return a top level environment */
samer@0 225 public static Environment top() {
samer@0 226 return new Environment(null,Node.root()) {
samer@0 227 public Binding add(String n, Object o) { throw error(); }
samer@0 228 public void add(Object o) { throw error(); }
samer@0 229 public void store(String nm, Object o, Codec c) { throw error(); }
samer@0 230 public void store(String nm, Autocoder o) { throw error(); }
samer@0 231
samer@0 232 public Datum datum() { return Null; }
samer@0 233 public Datum datum(String name) { return Null; }
samer@0 234 public Binding binding(String name) { return Null; }
samer@0 235
samer@0 236 public Iterator data() {
samer@0 237 return new Iterator() {
samer@0 238 public boolean hasNext() { return false; }
samer@0 239 public Datum next() { return Null; }
samer@0 240 };
samer@0 241 }
samer@0 242
samer@0 243 RuntimeException error() { return new RuntimeException("Environment.top"); }
samer@0 244 };
samer@0 245 }
samer@0 246 }
samer@0 247