00001
00002
00003
00004
00005
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
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
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044 {
00045
00046 std::string descr = path;
00047
00048
00049 const ph::common::object_base *o = obj;
00050
00051
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
00067 const ph::common::object_base *found_o = get_sub_object(o, part);
00068
00069
00070 if (!found_o)
00071 return 0;
00072
00073
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
00083
00084
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
00102
00103 {
00104
00105
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
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
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
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
00204 if (subs.length() == 0)
00205 {
00206
00207
00208 if (prop == "root")
00209 {
00210
00211 if (_debug)
00212 *_console << ">> returning root" << std::endl;
00213 return _root;
00214 }
00215 else if (prop == "parent")
00216 {
00217
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
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
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
00254
00255 if (prop == "parent")
00256 {
00257
00258 if (_debug)
00259 *_console << ">> parent(subscript)." << std::endl;
00260
00261
00262
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
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
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
00325
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
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
00370 if (_debug)
00371 *_console << ">> " << path << std::endl;
00372
00373
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
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 }