Main Page | Namespace List | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Namespace Members | Data Fields | Globals
reflect

jscript_object_navigator.cpp

Go to the documentation of this file.
00001 // See ../license.txt for license information.
00002 //
00003 // jscript_object_navigator.cpp
00004 //
00005 // 8-Jul-2003 phamilton Created
00006 //
00007 
00008 #define REFLECT_IN_LIBRARY_SOURCE
00009 
00010 #include "jscript_object_navigator.hpp"
00011 #include <iostream>
00012 #include "../common/object.hpp"
00013 #include "../common/composition_object.hpp"
00014 #include "../common/outerable_object.hpp"
00015 #include "../common/comparable_object.hpp"
00016 #include "../common/nameable_object.hpp"
00017 #include "jscript_object_nav_errors.h"
00018 #include "object_visitor.hpp"
00019 #include "member_visitor.hpp"
00020 #include <boost/lexical_cast.hpp>
00021 #include <boost/bind.hpp>
00022 
00023 using namespace ph::reflect;
00024 
00025 object_navigator *jscript_object_navigator_factory::create(const ph::common::object_base *root)
00026 {
00027 // use jscript style navigation.
00028 return new jscript_object_navigator(root, _console, _debug);
00029 }
00030 
00031 ph::common::object_base *jscript_object_navigator::navigate(const ph::common::object_base *obj, const std::string &path)
00032 /*
00033  Given the name of a sub-object, this function walks the 
00034  object tree and retrieves the named object.
00035 
00036  names are always relative to this object.
00037 
00038  root() - means the root of the object tree.
00039  parent(n) - means the nth (where the n can be left out) parent of this object.
00040 
00041  You can subscript a property if you know that the property is 
00042  a vector property,
00043 */
00044 {
00045 // start off with the path passed in.
00046 std::string descr = path;
00047 
00048 // start off with the object passed in.
00049 const ph::common::object_base *o = obj;
00050 
00051 // walk the dots in the string.
00052 int dot = find_span_quotes(descr, '.');
00053 std::string part = "";
00054 long parsed = dot;
00055 while (dot >= 0)
00056 {
00057 part = descr.substr(0, dot);
00058 descr = descr.substr(dot+1);
00059 
00060 if (part.empty())
00061 {
00062 error(e_empty_part, path.substr(parsed));
00063 return 0;
00064 }
00065 
00066 // get this piece.
00067 const ph::common::object_base *found_o = get_sub_object(o, part);
00068 
00069 // if the obj is NULL, then just successfully return a NULL object.
00070 if (!found_o)
00071 return 0;
00072 
00073 // next dot.
00074 o = found_o;
00075 parsed += dot;
00076 dot = find_span_quotes(descr, '.');
00077 }
00078 
00079 const ph::common::object_base *found_o = get_sub_object(o, descr);
00080 if (found_o)
00081 { 
00082 // although we don't modify any of the objects we visit, we do
00083 // need to return the actual object at the end, so
00084 // we cast out const.
00085 return const_cast<ph::common::object_base *>(found_o);
00086 }
00087 return 0;
00088 }
00089 
00090 static bool is_match_toggle_quotes(char i, char c, bool *inquotes)
00091 {
00092 if (i == '\'' || i == '"')
00093 *inquotes = !*inquotes;
00094 else if (!*inquotes && i == c)
00095 return true;
00096 return false;
00097 }
00098 
00099 int jscript_object_navigator::find_span_quotes(const std::string &s, char c)
00100 /*
00101  A simple find that can span quotes. This allows "." and "(" to appear in quotes.
00102 */
00103 {
00104 // a proper std::find_if would be nice here, but this will only
00105 // work efficiently if this function returns an iterator.
00106 bool inquotes = false;
00107 for (int i = 0; i < (int)s.size(); i++)
00108 if (is_match_toggle_quotes(s[i], c, &inquotes))
00109 return i;
00110 
00111 return -1;
00112 }
00113 
00114 void jscript_object_navigator::error(const std::string &msg, const std::string &name)
00115 {
00116 if (!_silent)
00117 *_console << "Syntax Error. " + msg + " [" << name << "]" << std::endl;
00118 }
00119 
00120 static std::string get_name(const ph::common::object_base *obj)
00121 {
00122 if (!obj->nameable())
00123 return "object has no nameable interface.";
00124 return obj->nameable()->name();
00125 }
00126 
00127 const ph::common::object_base *jscript_object_navigator::skip_composite(const ph::common::object_base *obj)
00128 {
00129 // skip over composite
00130 if (obj->composition() && obj->composition()->composite())
00131 return go_parent(obj);
00132 else
00133 return obj;
00134 }
00135 
00136 const ph::common::object_base *jscript_object_navigator::go_parent(const ph::common::object_base *obj)
00137 {
00138 if (obj->outerable())
00139 return obj->outerable()->outer();
00140 error(e_internal_no_outer_interface, get_name(obj));
00141 return 0;
00142 }
00143 
00144 const ph::common::object_base *jscript_object_navigator::get_composite(const ph::common::object_base *obj, const std::string &name)
00145 {
00146 if (!obj->visitable())
00147 {
00148 error(e_internal_no_reflect_interface, get_name(obj));
00149 return 0;
00150 }
00151 
00152 // the property may be a composite object reference (they don't subscript).
00153 get_composite_object_visitor v(name);
00154 obj->visitable()->accept(&v);
00155 return v.obj();
00156 }
00157 
00158 const ph::common::object_base *jscript_object_navigator::get_obj(const ph::common::object_base *obj, const std::string &name)
00159 {
00160 if (!obj->visitable())
00161 {
00162 error(e_internal_no_reflect_interface, get_name(obj));
00163 return 0;
00164 }
00165 
00166 get_object_visitor v(name);
00167 obj->visitable()->accept(&v);
00168 return v.obj();
00169 }
00170 
00171 const ph::common::object_base *jscript_object_navigator::get_nth_obj(const ph::common::object_base *obj, int n)
00172 {
00173 if (!obj->visitable())
00174 {
00175 error(e_internal_no_reflect_interface, get_name(obj));
00176 return 0;
00177 }
00178 
00179 if (_debug)
00180 *_console << ">> getting [" << n << "]." << std::endl;
00181 
00182 get_nth_object_visitor v(n);
00183 obj->visitable()->accept(&v);
00184 return v.obj();
00185 }
00186 
00187 const ph::common::object_base *jscript_object_navigator::get_sub_object(
00188 const ph::common::object_base *parent, const std::string &path)
00189 {
00190 if (_debug)
00191 *_console << ">> searching [" << get_name(parent) << "] for [" << path << "]" << std::endl;
00192 int br = path.find('(');
00193 if (br >= 0 && path[path.length()-1] == ')')
00194 {
00195 // syntax was object(something)
00196 
00197 std::string prop = path.substr(0, br);
00198 std::string subs = path.substr(br+1, path.length() - br - 2);
00199 
00200 if (_debug)
00201 *_console << ">> " << prop << "(" << subs << ")" << std::endl;
00202 
00203 // look at the special object references.
00204 if (subs.length() == 0)
00205 {
00206 // syntax was object()
00207 
00208 if (prop == "root")
00209 {
00210 // root()
00211 if (_debug)
00212 *_console << ">> returning root" << std::endl;
00213 return _root;
00214 }
00215 else if (prop == "parent")
00216 {
00217 // parent()
00218 const ph::common::object_base *obj = go_parent(parent);
00219 if (!obj)
00220 {
00221 error(e_internal_no_outer, prop);
00222 return 0;
00223 }
00224 
00225 // skip over composite
00226 obj = skip_composite(obj);
00227 
00228 if (_debug)
00229 *_console << ">> returning [" << (obj ? get_name(obj) : "null") << "]" << std::endl;
00230 
00231 return obj;
00232 }
00233 else
00234 {
00235 // see if the object to be found is a composite object, and if so return that.
00236 if (_debug)
00237 *_console << ">> " << prop << std::endl;
00238 
00239 const ph::common::object_base *c = get_composite(parent, prop);
00240 if (!c)
00241 {
00242 error(e_nobuiltin_or_composite, prop);
00243 return 0;
00244 }
00245 
00246 if (_debug)
00247 *_console << ">> returning [" << get_name(c) << "]" << std::endl;
00248 return c;
00249 }
00250 }
00251 else
00252 {
00253 // syntax was object(subscript)
00254 
00255 if (prop == "parent")
00256 {
00257 // syntax was parent(subscript)
00258 if (_debug)
00259 *_console << ">> parent(subscript)." << std::endl;
00260 
00261 // if the subscript has quotes around it, then use it as a string,
00262 // otherwise it's a number.
00263 if (subs[0] == '\'' && subs[subs.length()-1] == '\'')
00264 {
00265 std::string parentname = subs.substr(1, subs.length()-2);
00266 bool found = false;
00267 const ph::common::object_base *pn = go_parent(parent);
00268 while (pn && !found)
00269 {
00270 if (get_name(pn) == parentname)
00271 found = true;
00272 else
00273 pn = go_parent(pn);
00274 }
00275 if (!found)
00276 {
00277 error(e_no_parent, parentname);
00278 return 0;
00279 }
00280 
00281 return pn;
00282 }
00283 else
00284 {
00285 int count = boost::lexical_cast<long>(subs);
00286 const ph::common::object_base *pn = go_parent(parent);
00287 if (!pn)
00288 {
00289 error(e_internal_no_outer, subs);
00290 return 0;
00291 }
00292 
00293 // skip over composite
00294 pn = skip_composite(pn);
00295 while (pn && --count > 0)
00296 {
00297 pn = go_parent(pn);
00298 if (pn)
00299 pn = skip_composite(pn);
00300 }
00301 
00302 if (!pn)
00303 {
00304 error(e_no_nth_parent, subs);
00305 return 0;
00306 }
00307 
00308 return pn;
00309 }
00310 }
00311 else
00312 {
00313 // syntax was object(subscript)
00314 if (_debug)
00315 *_console << ">> object(subscript)." << std::endl;
00316 
00317 const ph::common::object_base *c = get_composite(parent, prop);
00318 if (!c)
00319 {
00320 error(e_no_composite, prop);
00321 return 0;
00322 }
00323 
00324 // if the subscript has quotes around it, then use it as a string,
00325 // otherwise it's a number.
00326 if (subs[0] == '\'' && subs[subs.length()-1] == '\'')
00327 {
00328 if (_debug)
00329 *_console << ">> object string subscript." << std::endl;
00330 
00331 const ph::common::object_base *obj = get_obj(c, subs.substr(1, subs.length()-2));
00332 if (!obj)
00333 {
00334 error(e_no_named_object, subs);
00335 return 0;
00336 }
00337 
00338 if (_debug)
00339 *_console << ">> returning [" << get_name(obj) << "]" << std::endl;
00340 
00341 return obj;
00342 }
00343 else
00344 {
00345 if (_debug)
00346 *_console << ">> object nth subscript." << std::endl;
00347 
00348 // for the end user, we use 1 based subscripts.
00349 const ph::common::object_base *obj = get_nth_obj(c, boost::lexical_cast<long>(subs)-1);
00350 if (!obj)
00351 {
00352 error(e_no_nth_object, subs);
00353 return 0;
00354 }
00355 
00356 if (_debug)
00357 *_console << ">> returning [" << get_name(obj) << "]" << std::endl;
00358 
00359 if (obj->comparable() && obj->comparable()->equal(c))
00360 *_console << ">> object returned was same as composite?." << std::endl;
00361 
00362 return obj;
00363 }
00364 }
00365 }
00366 }
00367 else
00368 {
00369 // syntax was object.object. This will only work for singleton composites.
00370 if (_debug)
00371 *_console << ">> " << path << std::endl;
00372 
00373 // the property may be a composite object reference (they don't subscript).
00374 const ph::common::object_base *c = get_composite(parent, path);
00375 if (!c)
00376 {
00377 error(e_no_composite, path);
00378 return 0;
00379 }
00380 
00381 // if we have no composite interface, then it can't be a singleton composite.
00382 if (c->composition() && c->composition()->composite() && !c->composition()->composite()->singleton())
00383 {
00384 error(e_not_singleton_composite, path);
00385 return 0;
00386 }
00387 
00388 const ph::common::object_base *obj = get_nth_obj(c, 0);
00389 if (!obj)
00390 {
00391 error(e_empty_singleton_composite, path);
00392 return 0;
00393 }
00394 
00395 if (_debug)
00396 *_console << ">> returning [" << get_name(obj) << "]" << std::endl;
00397 
00398 return obj;
00399 }
00400 
00401 error(e_internal_get_sub_object_reached_end, path);
00402 return 0;
00403 }

Generated on Wed Apr 5 22:03:24 2006 for cppxmlobj by doxygen 1.4.3

AltStyle によって変換されたページ (->オリジナル) /