Annotation of parser3/src/classes/reflection.C, revision 1.99
1.1 misha 1: /** @file
2: Parser: @b reflection parser class.
3:
1.94 moko 4: Copyright (c) 2001-2024 Art. Lebedev Studio (http://www.artlebedev.com)
1.89 moko 5: Authors: Konstantin Morshnev <moko@design.ru>, Alexandr Petrosian <paf@design.ru>
1.1 misha 6: */
7:
8: #include "pa_vmethod_frame.h"
9: #include "pa_request.h"
10: #include "pa_vbool.h"
1.95 moko 11: #include "pa_varray.h"
1.50 moko 12: #include "pa_vobject.h"
1.1 misha 13:
1.99 ! moko 14: volatile const char * IDENT_REFLECTION_C="$Id: reflection.C,v 1.98 2025/05/26 00:52:15 moko Exp $";
1.24 moko 15:
1.3 misha 16: static const String class_type_methoded("methoded");
1.2 misha 17:
1.3 misha 18: static const String method_type_native("native");
19: static const String method_type_parser("parser");
1.2 misha 20:
1.59 moko 21: static const String method_name("name");
1.71 moko 22: static const String method_class_name("class");
1.5 misha 23: static const String method_call_type("call_type");
1.8 misha 24: static const String method_inherited("inherited");
1.23 misha 25: static const String method_overridden("overridden");
1.2 misha 26:
1.3 misha 27: static const String method_min_params("min_params");
28: static const String method_max_params("max_params");
1.29 misha 29: static const String method_extra_param("extra_param");
1.95 moko 30: static const String method_named_params("named_params");
1.2 misha 31:
1.30 misha 32: static const String def_class("class");
33:
1.1 misha 34: // class
35:
36: class MReflection: public Methoded {
37: public:
38: MReflection();
39: };
40:
41: // global variable
42:
1.40 moko 43: DECLARE_CLASS_VAR(reflection, new MReflection);
1.1 misha 44:
45: // methods
46:
1.73 moko 47: const int MAX_CREATE_PARAMS = 100;
1.2 misha 48:
49: static void _create(Request& r, MethodParams& params) {
1.73 moko 50: int params_offset;
51: HashStringValue* params_hash=0;
52:
53: const String* class_name=0;
54: const String* constructor_name=0;
55:
1.75 moko 56: Value& voptions=params.as_no_junction(0, "param must not be code");
1.73 moko 57: if(HashStringValue* options=voptions.get_hash()) {
58: int valid_options=0;
59: if(Value* vclass_name=options->get("class")) {
60: valid_options++;
61: class_name=&vclass_name->as_string();
62: }
63: if(Value* vconstructor_name=options->get("constructor")) {
64: valid_options++;
65: constructor_name=&vconstructor_name->as_string();
66: }
67: if(Value* vparams_hash=options->get("arguments")) {
68: valid_options++;
69: params_hash=vparams_hash->as_hash("arguments");
70: if(params.count()>1)
1.86 moko 71: throw Exception(PARSER_RUNTIME, 0, "arguments should not be specified as hash and as create params");
1.73 moko 72: }
73: if(valid_options!=options->count())
74: throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION);
75:
76: if(!class_name)
77: throw Exception(PARSER_RUNTIME, 0, "class name must be specified");
78: if(!constructor_name)
79: throw Exception(PARSER_RUNTIME, 0, "constructor name must be specified");
80:
81: params_offset=1;
82: } else {
1.75 moko 83: class_name=¶ms.as_string(0, "param must not be code");
1.73 moko 84:
85: if(params.count()==1)
86: throw Exception(PARSER_RUNTIME, 0, "constructor name must be specified");
87:
88: constructor_name=¶ms.as_string(1, "constructor name must be string");
89:
90: params_offset=2;
91: }
1.1 misha 92:
1.88 moko 93: VStateless_class& vclass=r.get_class_ref(*class_name);
1.1 misha 94:
1.88 moko 95: const Method* method=vclass.get_method(*constructor_name);
1.73 moko 96: if(!method)
1.88 moko 97: throw Exception(PARSER_RUNTIME, constructor_name, "constructor not found in class '%s'", vclass.type());
1.1 misha 98:
1.88 moko 99: Value &object = r.construct(vclass, *method);
1.2 misha 100:
1.73 moko 101: int nparams=params_hash ? params_hash->count() : (params.count()-params_offset);
102: if(nparams>MAX_CREATE_PARAMS)
103: throw Exception(PARSER_RUNTIME, 0, "arguments count should not exceed %d", MAX_CREATE_PARAMS);
1.1 misha 104:
1.74 moko 105: Value* args[MAX_CREATE_PARAMS];
1.65 moko 106: CONSTRUCTOR_FRAME_ACTION(*method, r.get_method_frame(), object, {
107: if(nparams>0){
1.73 moko 108: if(params_hash){
1.74 moko 109: int i=0;
110: for(HashStringValue::Iterator h(*params_hash); h; h.next())
111: args[i++]=h.value();
1.73 moko 112: } else {
113: for(int i=0; i<nparams; i++)
1.74 moko 114: args[i]=&r.process(params[i+params_offset]);
1.73 moko 115: }
1.74 moko 116: frame.store_params((Value**)&args, nparams);
1.65 moko 117: } else {
118: frame.empty_params();
119: }
120: r.call(frame);
121: object.enable_default_setter();
122: r.write(frame.result());
123: });
1.1 misha 124: }
125:
1.2 misha 126:
1.3 misha 127: static void _classes(Request& r, MethodParams&) {
128: VHash& result=*new VHash;
1.47 moko 129: for(HashString<VStateless_class*>::Iterator i(r.classes()); i; i.next()){
130: result.hash().put(i.key(), i.value()->get_methods().count()>0 ? new VString(class_type_methoded) : VVoid::get() );
131: }
1.64 moko 132: r.write(result);
1.3 misha 133: }
134:
135:
1.53 moko 136: static Value& get_class(Value& value){
137: if(VStateless_class* result=value.get_class())
138: return *result;
139: else {
140: // we can't return code junction to outside as it's stack value
141: if(Junction *j=value.get_junction())
142: if(j->code)
143: throw Exception(PARSER_RUNTIME, 0, "param must not be code junction");
144: // method junction
1.3 misha 145: return value;
1.53 moko 146: }
1.3 misha 147: }
148:
1.53 moko 149: static const String& get_class_name(Value& value){
150: return *new String(get_class(value).type());
1.3 misha 151: }
152:
153:
1.1 misha 154: static void _class(Request& r, MethodParams& params) {
1.64 moko 155: r.write(get_class(params[0]));
1.1 misha 156: }
157:
1.2 misha 158:
1.1 misha 159: static void _class_name(Request& r, MethodParams& params) {
1.64 moko 160: r.write(get_class_name(params[0]));
1.1 misha 161: }
162:
1.34 moko 163: static void _class_by_name(Request& r, MethodParams& params) {
1.99 ! moko 164: const String& class_name=params.as_string(0, "class name must be string");
1.88 moko 165: r.write(r.get_class_ref(class_name));
1.34 moko 166: }
1.1 misha 167:
1.91 moko 168: static void _class_alias(Request& r, MethodParams& params) {
169: const String& src_class_name=params.as_string(0, "source class_name must be string");
170: const String& new_class_name=params.as_string(1, "alias class_name must be string");
171:
172: VStateless_class &src_class=r.get_class_ref(src_class_name);
173: if(!r.add_class(new_class_name.cstr(), &src_class))
174: throw Exception(PARSER_RUNTIME, &new_class_name, "class is already defined");
175: }
176:
1.2 misha 177: static void _base(Request& r, MethodParams& params) {
1.49 moko 178: if(VStateless_class* vclass=params[0].get_class())
179: if(Value* base=vclass->base()){
1.64 moko 180: r.write(get_class(*base));
1.3 misha 181: return;
182: }
183:
184: // classes with fields only, like env & console or without base
1.52 moko 185: r.write_value(*VVoid::get());
1.2 misha 186: }
1.1 misha 187:
188:
1.2 misha 189: static void _base_name(Request& r, MethodParams& params) {
1.49 moko 190: if(VStateless_class* vclass=params[0].get_class())
191: if(Value* base=vclass->base())
1.64 moko 192: r.write(get_class_name(*base));
1.2 misha 193: }
1.1 misha 194:
1.30 misha 195: static void _def(Request& r, MethodParams& params) {
196: const String& type=params.as_string(0, "type must be string");
197: if(type == def_class) {
198: const String& name=params.as_string(1, "name must be string");
1.47 moko 199: // can't use get_class because it will call @autouse[] if the class wasn't loaded
1.64 moko 200: r.write(VBool::get(r.classes().get(name)!=0));
1.30 misha 201: } else {
1.93 moko 202: throw Exception(PARSER_RUNTIME, &type, "is an invalid type, must be '%s'", def_class.cstr());
1.30 misha 203: }
204: }
205:
1.1 misha 206: static void _methods(Request& r, MethodParams& params) {
207: const String& class_name=params.as_string(0, "class_name must be string");
1.88 moko 208: VStateless_class& vclass=r.get_class_ref(class_name);
1.1 misha 209:
1.84 moko 210: bool reverse=true;
211:
212: if(params.count()>1)
213: if(HashStringValue* options=params.as_hash(1, "methods options")) {
214: int valid_options=0;
215: for(HashStringValue::Iterator i(*options); i; i.next() ){
216: String::Body key=i.key();
217: Value* value=i.value();
218: if(key == "reverse") {
219: reverse=r.process(*value).as_bool();
220: valid_options++;
221: }
222: }
223: if(valid_options!=options->count())
224: throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION);
225: }
226:
1.1 misha 227: VHash& result=*new VHash;
1.84 moko 228:
1.85 moko 229: #ifdef HASH_ORDER
1.84 moko 230: if(reverse){
1.88 moko 231: for(HashStringMethod::ReverseIterator i(vclass.get_methods()); i; i.prev()){
1.84 moko 232: result.hash().put(i.key(), new VString(i.value()->native_code ? method_type_native : method_type_parser));
233: }
234: } else {
1.85 moko 235: #else
236: {
237: #endif
1.88 moko 238: for(HashStringMethod::Iterator i(vclass.get_methods()); i; i.next()){
1.84 moko 239: result.hash().put(i.key(), new VString(i.value()->native_code ? method_type_native : method_type_parser));
240: }
1.1 misha 241: }
1.49 moko 242:
1.64 moko 243: r.write(result);
1.1 misha 244: }
245:
1.57 moko 246: static VJunction &method_junction(Value &self, Method &method){
1.50 moko 247: if(method.native_code)
1.57 moko 248: throw Exception(PARSER_RUNTIME, method.name, "method must not be native");
1.50 moko 249:
1.51 moko 250: if(!(dynamic_cast<VObject*>(&self) || dynamic_cast<VClass*>(&self)))
251: throw Exception(PARSER_RUNTIME, 0, "self must be parser object or class");
1.50 moko 252:
253: return *method.get_vjunction(self);
254: }
255:
1.28 misha 256: static void _method(Request& r, MethodParams& params) {
1.62 moko 257: Value &source=params[0];
1.50 moko 258:
259: if(Junction *j=source.get_junction()){
260: if(Method* method=const_cast<Method*>(j->method)){
1.96 moko 261: Value& self=params.count()>1 ? params.as_no_junction(1, "self must be object") : r.get_method_frame()->caller()->self();
1.64 moko 262: r.write(method_junction(self, *method));
1.50 moko 263: return;
264: }
1.51 moko 265: throw Exception(PARSER_RUNTIME, 0, "param must be method junction");
1.50 moko 266: }
267:
268: if(params.count()==1)
1.51 moko 269: throw Exception(PARSER_RUNTIME, 0, "method name must be specified");
1.50 moko 270:
1.28 misha 271: const String& name=params.as_string(1, "method name must be string");
272:
1.50 moko 273: if(VStateless_class* vclass=source.get_class()) {
274: if(Method* method=vclass->get_method(name)){
1.96 moko 275: r.write( params.count()>2 ? method_junction(params.as_no_junction(2, "self must be object"), *method) : *method->get_vjunction(source) );
1.50 moko 276: return;
277: }
1.28 misha 278: }
1.52 moko 279: r.write_value(*VVoid::get());
1.28 misha 280: }
281:
1.13 misha 282: static void _fields(Request& r, MethodParams& params) {
1.96 moko 283: Value& o=params.as_no_junction(0, "param must be object or class");
1.28 misha 284:
1.44 moko 285: if(HashStringValue* fields=o.get_fields())
1.64 moko 286: r.write(*new VHash(*fields));
1.44 moko 287: else
1.64 moko 288: r.write(*new VHash());
1.13 misha 289: }
1.2 misha 290:
1.44 moko 291: static void _fields_reference(Request& r, MethodParams& params) {
1.96 moko 292: Value& o=params.as_no_junction(0, "param must be object or hash");
1.44 moko 293:
1.45 moko 294: if(HashStringValue* fields=o.get_fields_reference())
1.64 moko 295: r.write(*new VHashReference(*fields));
1.44 moko 296: else
1.46 moko 297: throw Exception(PARSER_RUNTIME, 0, "param must be object or hash");
1.44 moko 298: }
299:
1.28 misha 300: static void _field(Request& r, MethodParams& params) {
1.96 moko 301: Value& o=params.as_no_junction(0, "first param must be object or class");
1.28 misha 302: const String& name=params.as_string(1, "field name must be string");
303:
304: if(HashStringValue* fields=o.get_fields())
305: if(Value* value=fields->get(name))
1.64 moko 306: r.write(*value);
1.28 misha 307: }
308:
1.8 misha 309: static void _method_info(Request& r, MethodParams& params) {
1.59 moko 310: const Method* method;
1.66 moko 311:
312: VHash& result=*new VHash;
313: HashStringValue* hash=result.get_hash();
1.2 misha 314:
1.62 moko 315: if(Junction *j=params[0].get_junction()){
1.59 moko 316: if(!(method=j->method))
317: throw Exception(PARSER_RUNTIME, 0, "param must be class name or method junction");
1.66 moko 318:
319: hash->put(method_name, new VString(*method->name));
1.71 moko 320: hash->put(method_class_name, new VString(*new String(j->self.type())));
321:
1.59 moko 322: } else {
323: const String& class_name=params.as_string(0, "param must be class name or method junction");
1.88 moko 324: VStateless_class& vclass=r.get_class_ref(class_name);
1.59 moko 325:
326: if(params.count()==1)
327: throw Exception(PARSER_RUNTIME, 0, "method name must be specified");
328:
329: const String& method_name=params.as_string(1, "method name must be string");
1.88 moko 330: if(!(method=vclass.get_method(method_name)))
331: throw Exception(PARSER_RUNTIME, &method_name, "method not found in class '%s'", vclass.type());
1.2 misha 332:
1.66 moko 333: Method* base_method;
1.88 moko 334: if(vclass.base() && (base_method=vclass.base()->get_method(*method->name))){
335: VStateless_class* c=vclass.base()->get_class();
1.66 moko 336: while(c->base() && base_method==c->base()->get_method(*method->name))
337: c=c->base()->get_class();
338: hash->put((base_method==method) ? method_inherited : method_overridden, new VString(*new String(c->type())));
339: }
1.23 misha 340: }
1.8 misha 341:
1.29 misha 342: Value* call_type=0;
343: switch(method->call_type){
344: case Method::CT_DYNAMIC:
1.42 moko 345: call_type=new VString(Symbols::DYNAMIC_SYMBOL);
1.29 misha 346: break;
347: case Method::CT_STATIC:
1.42 moko 348: call_type=new VString(Symbols::STATIC_SYMBOL);
1.29 misha 349: break;
1.32 moko 350: case Method::CT_ANY:
351: break;
1.29 misha 352: }
353: if(call_type)
354: hash->put(method_call_type, call_type);
355:
1.2 misha 356: if(method->native_code){
357: // native code
358: hash->put(method_min_params, new VInt(method->min_numbered_params_count));
359: hash->put(method_max_params, new VInt(method->max_numbered_params_count));
360: } else {
361: // parser code
1.68 moko 362: const String* filespec = r.get_method_filespec(method);
1.16 misha 363: if( filespec )
1.98 moko 364: HASH_PUT_CSTR(*hash, "file", new VString(*filespec));
1.29 misha 365:
1.95 moko 366: hash->put(method_max_params, new VInt(method->params_count + (method->named_params ? 1 : 0)));
1.29 misha 367:
1.2 misha 368: if(method->params_names)
369: for(size_t i=0; i<method->params_names->count(); i++)
1.98 moko 370: hash->put(String::Body::uitoa(i), new VString(*method->params_names->get(i)));
1.29 misha 371:
372: if(method->extra_params)
373: hash->put(method_extra_param, new VString(*method->extra_params));
1.95 moko 374: if(method->named_params){
375: size_t named_count=method->named_params->count();
376: VArray& named_params=*new VArray(named_count);
377: ArrayValue &array=named_params.array();
378:
1.97 moko 379: for(size_t i=0; i<named_count; i++) {
1.95 moko 380: const String& fname=*(*method->named_params)[i];
381: array+=new VString(fname);
382: }
383: hash->put(method_named_params, &named_params);
384: }
1.2 misha 385: }
386:
1.64 moko 387: r.write(result);
1.2 misha 388: }
389:
1.67 moko 390: static void _filename(Request& r, MethodParams& params) {
1.68 moko 391: if(Junction *j=params[0].get_junction()){
392: if(const Method* method=j->method){
393: if(!method->native_code)
394: if(const String* filespec = r.get_method_filespec(method))
395: r.write(*new VString(*filespec));
396: return;
397: }
398: throw Exception(PARSER_RUNTIME, 0, "param must be object, class or method junction");
399: }
1.67 moko 400:
1.68 moko 401: if(VClass* vclass = dynamic_cast<VClass*>(params[0].get_class())){
402: r.write(*new VString(vclass->get_filespec()));
1.67 moko 403: }
404: }
405:
1.9 misha 406: static void _dynamical(Request& r, MethodParams& params) {
407: if(params.count()){
1.64 moko 408: r.write(VBool::get(params[0].get_class() != ¶ms[0]));
1.9 misha 409: } else {
410: VMethodFrame* caller=r.get_method_frame()->caller();
1.64 moko 411: r.write(VBool::get(caller && caller->get_class() != &caller->self()));
1.9 misha 412: }
413: }
414:
1.35 moko 415: static void _is(Request& r, MethodParams& params) {
1.39 moko 416: const String& name=params.as_string(0, "element name must be string");
417: const String& type=params.as_string(1, "class name must be string");
418: Value *context=params.count()==3 ? &(params.as_no_junction(2, "context must not be code")) : r.get_method_frame()->caller();
1.37 moko 419: Value *value=context ? context->get_element(name) : 0;
1.35 moko 420:
421: if(value) {
422: if(type == "code" || type == "method") {
423: Junction *junction=value->get_junction();
1.64 moko 424: r.write(VBool::get(junction && ((junction->code==0) ^ (type == "code"))) );
1.35 moko 425: } else {
1.64 moko 426: r.write(VBool::get( value->is(type.cstr()) ));
1.35 moko 427: }
428: } else
1.64 moko 429: r.write(VBool::get(type == "void"));
1.35 moko 430: }
431:
1.19 moko 432: static void _copy(Request& r, MethodParams& params) {
433: HashStringValue* src=params.as_no_junction(0, "source must not be code").get_hash();
434:
1.44 moko 435: if(src==NULL)
1.19 moko 436: throw Exception(PARSER_RUNTIME, 0, "source must have hash representation");
437:
438: Value& dst=params.as_no_junction(1, "destination must not be code");
439:
440: for(HashStringValue::Iterator i(*src); i; i.next())
1.20 moko 441: r.put_element(dst, *new String(i.key(), String::L_TAINTED), i.value());
1.19 moko 442: }
443:
1.25 moko 444: static void _uid(Request& r, MethodParams& params) {
445: Value& obj=params.as_no_junction(0, "object must not be code");
446:
447: char local_buf[MAX_NUMBER];
448: int size=snprintf(local_buf, sizeof(local_buf), "%p", &obj);
449:
1.64 moko 450: r.write(*new String(String::C(pa_strdup(local_buf, (size_t)size), size)));
1.25 moko 451: }
452:
1.27 moko 453: static void _delete(Request&, MethodParams& params) {
1.96 moko 454: Value* v=¶ms.as_no_junction(0, "param must be object or class");
1.26 misha 455: const String& key=params.as_string(1, "field name must be string");
1.58 moko 456:
457: if(VObject* o=dynamic_cast<VObject*>(v)){
458: o->get_fields()->remove(key);
459: } else if(VClass* c=dynamic_cast<VClass*>(v)){
460: HashStringProperty &p=*c->get_properties();
461: if(Property* property=p.get(key))
462: if(property->value)
463: p.remove(key);
1.26 misha 464: }
465: }
466:
1.55 moko 467: static void _mixin(Request& r, MethodParams& params) {
468: Value& vsource=params.as_no_junction(0, "source must not be code");
469:
470: Value* vtarget=0;
471: const String *name=0;
472: bool copy_methods=true;
473: bool copy_fields=true;
1.60 moko 474: bool overwrite=false;
1.55 moko 475:
476: if(params.count()>1)
477: if(HashStringValue* options=params.as_hash(1, "mixin options")) {
478: int valid_options=0;
1.80 moko 479: for(HashStringValue::Iterator i(*options); i; i.next() ){
480: String::Body key=i.key();
481: Value* value=i.value();
482: if(key == "to") {
483: vtarget=value;
484: valid_options++;
485: } else if(key == "name") {
486: name=&value->as_string();
487: valid_options++;
488: } else if(key == "methods") {
489: copy_methods=r.process(*value).as_bool();
490: valid_options++;
491: } else if(key == "fields") {
492: copy_fields=r.process(*value).as_bool();
493: valid_options++;
494: } else if(key == "overwrite") {
495: overwrite=r.process(*value).as_bool();
496: valid_options++;
497: }
1.55 moko 498: }
499: if(valid_options!=options->count())
500: throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION);
501: }
502:
503: if(!vtarget)
504: vtarget=&r.get_method_frame()->caller()->self();
505:
506: VClass* source=dynamic_cast<VClass*>(vsource.get_class());
507: VClass* target=dynamic_cast<VClass*>(vtarget->get_class());
508:
509: if(!source)
510: throw Exception(PARSER_RUNTIME, 0, "source must be parser object or class");
511: if(!target)
512: throw Exception(PARSER_RUNTIME, 0, "destination must be parser object or class");
513:
514: if(name){
515: if(copy_methods)
516: if(Method* method=source->get_method(*name))
517: if(overwrite || !target->get_method(*name)){
1.59 moko 518: target->set_method(*name, new Method(*method));
1.55 moko 519: }
520:
521: if(copy_fields)
522: if(Property* property=source->get_properties()->get(*name))
523: if(property->value && (overwrite || !target->get_properties()->get(*name))){
524: target->put_element(*target, *name, property->value);
525: }
526:
527: } else {
528: if(copy_methods)
529: for(HashStringMethod::Iterator i(source->get_methods()); i; i.next()){
530: if(overwrite || !target->get_method(i.key()))
1.59 moko 531: target->set_method(*i.value()->name, new Method(*i.value()));
1.55 moko 532: }
533: if(copy_fields)
534: for(HashStringProperty::Iterator i(*source->get_properties()); i; i.next()){
535: if(i.value()->value && ( overwrite || !target->get_properties()->get(i.key()) ))
536: target->put_element(*target, *new String(i.key(), String::L_TAINTED), i.value()->value);
537: }
538: }
539: }
540:
1.99 ! moko 541: static void _override(Request& r, MethodParams& params) {
! 542: Junction *j=params[0].get_junction();
! 543: const Method* method=j ? j->method : 0;
! 544: if(!method)
! 545: throw Exception(PARSER_RUNTIME, 0, "param must be method junction");
! 546:
! 547: const String *name=method->name;
! 548: Value* vtarget=0;
! 549: if(params.count()>1)
! 550: if(HashStringValue* options=params.as_hash(1, "override options")) {
! 551: int valid_options=0;
! 552: for(HashStringValue::Iterator i(*options); i; i.next() ){
! 553: if(i.key() == "to") {
! 554: vtarget=i.value();
! 555: valid_options++;
! 556: } else if(i.key() == "name") {
! 557: name=&i.value()->as_string();
! 558: valid_options++;
! 559: }
! 560: }
! 561: if(valid_options!=options->count())
! 562: throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION);
! 563: }
! 564:
! 565: if(!vtarget)
! 566: vtarget=&r.get_method_frame()->caller()->self();
! 567:
! 568: VClass* target=dynamic_cast<VClass*>(vtarget->get_class());
! 569:
! 570: if(!target)
! 571: throw Exception(PARSER_RUNTIME, 0, "destination must be parser object or class");
! 572:
! 573: target->set_method(*name, new Method(*method));
! 574: }
! 575:
1.76 moko 576: String::Language get_untaint_lang(const String& lang_name); // op.C
577:
578: static void _tainting(Request& r, MethodParams& params) {
1.78 moko 579: const String& str=params.as_string(params.count()-1, "param must be string");
1.76 moko 580: String::Language lang = String::L_UNSPECIFIED;
581: bool optimized=false;
582:
583: if(params.count()==2){
1.78 moko 584: const String& slang=params.as_string(0, "language name must be string");
1.76 moko 585: if(slang == "optimized")
586: optimized=true;
587: else if(slang == "tainted")
588: lang=String::L_TAINTED;
589: else lang=get_untaint_lang(slang);
590: }
591:
592: if(!str.is_empty()){
593: char *visual=str.visualize_langs();
594:
595: if(optimized){
596: for(char *c=visual; *c; c++)
597: *c = *c<0 ? '+':'-';
598: } else if(lang != String::L_UNSPECIFIED){
599: for(char *c=visual; *c; c++)
600: *c = *c==lang ? '+':'-';
601: } else {
602: for(char *c=visual; *c; c++)
603: *c = *c & 0x7F;
604: }
605:
606: r.write(*new String(visual));
607: }
608: }
1.26 misha 609:
1.81 moko 610: static void _stack(Request& r, MethodParams& params) {
611: bool show_args=false;
612: bool show_locals=false;
613:
614: int limit=1000000;
615: int offset=0;
616:
617: if(params.count()>0)
618: if(HashStringValue* options=params.as_hash(0, "stack options")) {
619: int valid_options=0;
620: for(HashStringValue::Iterator i(*options); i; i.next() ){
621: String::Body key=i.key();
622: Value* value=i.value();
623:
624: if(key == "args") {
625: show_args=r.process(*value).as_bool();
626: valid_options++;
1.82 moko 627: } else if(key == "locals") {
1.81 moko 628: show_locals=r.process(*value).as_bool();
629: valid_options++;
1.82 moko 630: } else if(key == "limit") {
1.81 moko 631: limit=r.process(*value).as_int();
632: valid_options++;
1.82 moko 633: } else if(key == "offset") {
1.81 moko 634: offset=r.process(*value).as_int();
635: valid_options++;
636: }
637: }
638:
639: if(valid_options!=options->count())
640: throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION);
641: }
642:
643: limit+=offset;
644:
645: VHash& vresult=*new VHash;
646: HashStringValue* result=vresult.get_hash();
647: int index=1;
648: VMethodFrame* caller=r.get_method_frame()->caller();
649: while(caller && index <= limit){
650: if(index>offset){
651: VHash& vcurrent=*new VHash;
652: HashStringValue* current=vcurrent.get_hash();
653:
654: current->put(Symbols::SELF_SYMBOL, &caller->self());
655:
656: const Method& method=caller->method;
657:
658: current->put(method_name, new VString(*method.name));
659:
660: if(!method.native_code){
661: Operation::Origin origin=r.get_method_origin(&method);
662: if(origin.file_no){
1.98 moko 663: HASH_PUT_CSTR(*current, "file", new VString(*r.get_used_filespec(origin.file_no)));
664: HASH_PUT_CSTR(*current, "line", new VInt(origin.line)); // no +1 as declaration before first command
1.81 moko 665: }
666:
667: if(show_args || show_locals){
668:
669: VHash& vargs=*new VHash;
670: HashStringValue* args=vargs.get_hash();
671:
672: if(method.params_names){
673: for(size_t i=0; i<method.params_names->count(); i++){
674: const String& pname=*(*method.params_names)[i];
675: Value* value=caller->get_element(pname);
676: args->put(pname, value->get_junction() ? VVoid::get() : value);
677: }
678: }
679: if(method.extra_params)
680: args->put(*method.extra_params, caller->get_element(*method.extra_params));
681:
682: if(show_args)
1.98 moko 683: HASH_PUT_CSTR(*current, "args", &vargs);
1.81 moko 684:
685: if(show_locals){
686: VHash& vlocals=*new VHash;
687: HashStringValue* locals=vlocals.get_hash();
688:
689: if(VParserMethodFrame* frame=dynamic_cast<VParserMethodFrame*>(caller))
690: for(HashString<Value*>::Iterator h(frame->my); h; h.next()){
691: String::Body key=h.key();
692: Value* value=h.value();
693: if(!args->contains(key) && (key != "result")){
694: locals->put(key, value->get_junction() ? VVoid::get() : value);
695: }
696: }
697:
1.98 moko 698: HASH_PUT_CSTR(*current, "locals", &vlocals);
1.81 moko 699: }
700: }
701: }
702:
1.98 moko 703: result->put(String::Body::uitoa(index), &vcurrent);
1.81 moko 704: }
705: caller=caller->caller();
706: index++;
707: }
708:
709: r.write(vresult);
710: }
711:
1.1 misha 712: // constructor
713: MReflection::MReflection(): Methoded("reflection") {
1.2 misha 714: // ^reflection:create[class_name;constructor_name[;param1[;param2[;...]]]]
1.73 moko 715: // ^reflection:create[ $.class[name] $.constructor[name] $.arguments[ $.1[param1] $.2[param2] ...] ]
716: add_native_method("create", Method::CT_STATIC, _create, 1, MAX_CREATE_PARAMS + 2);
1.1 misha 717:
1.3 misha 718: // ^reflection:classes[]
719: add_native_method("classes", Method::CT_STATIC, _classes, 0, 0);
720:
1.1 misha 721: // ^reflection:class[object]
722: add_native_method("class", Method::CT_STATIC, _class, 1, 1);
723:
724: // ^reflection:class_name[object]
725: add_native_method("class_name", Method::CT_STATIC, _class_name, 1, 1);
726:
1.34 moko 727: // ^reflection:class_by_name[class_name]
728: add_native_method("class_by_name", Method::CT_STATIC, _class_by_name, 1, 1);
729:
1.91 moko 730: // ^reflection:class_alias[class_name;new_class_name]
731: add_native_method("class_alias", Method::CT_STATIC, _class_alias, 2, 2);
732:
1.2 misha 733: // ^reflection:base_class[object]
734: add_native_method("base", Method::CT_STATIC, _base, 1, 1);
735:
736: // ^reflection:base_class_name[object]
737: add_native_method("base_name", Method::CT_STATIC, _base_name, 1, 1);
738:
1.30 misha 739: // ^reflection:def[class|...;name]
740: add_native_method("def", Method::CT_STATIC, _def, 2, 2);
741:
1.2 misha 742: // ^reflection:methods[class_name]
1.84 moko 743: add_native_method("methods", Method::CT_STATIC, _methods, 1, 2);
1.2 misha 744:
1.54 moko 745: // ^reflection:method[object or class;method_name[;self]]
746: // ^reflection:method[junction[;self]]
1.50 moko 747: add_native_method("method", Method::CT_STATIC, _method, 1, 3);
1.28 misha 748:
749: // ^reflection:method_info[class_name;method_name]
1.59 moko 750: // ^reflection:method_info[junction]
751: add_native_method("method_info", Method::CT_STATIC, _method_info, 1, 2);
1.28 misha 752:
1.79 moko 753: // ^reflection:filename[object or class or method]
1.67 moko 754: add_native_method("filename", Method::CT_STATIC, _filename, 1, 1);
755:
1.13 misha 756: // ^reflection:fields[object or class]
757: add_native_method("fields", Method::CT_STATIC, _fields, 1, 1);
758:
1.44 moko 759: // ^reflection:fields_reference[object]
760: add_native_method("fields_reference", Method::CT_STATIC, _fields_reference, 1, 1);
761:
1.28 misha 762: // ^reflection:field[object or class;field_name]
763: add_native_method("field", Method::CT_STATIC, _field, 2, 2);
1.9 misha 764:
765: // ^reflection:dynamical[[object or class, caller if absent]]
766: add_native_method("dynamical", Method::CT_STATIC, _dynamical, 0, 1);
1.19 moko 767:
1.39 moko 768: // ^reflection:is[element_name;class_name|code|method[;context]]
1.35 moko 769: add_native_method("is", Method::CT_STATIC, _is, 2, 3);
770:
1.19 moko 771: // ^reflection:copy[src;dst]
772: add_native_method("copy", Method::CT_STATIC, _copy, 2, 2);
1.25 moko 773:
774: // ^reflection:uid[object or class]
775: add_native_method("uid", Method::CT_STATIC, _uid, 1, 1);
1.26 misha 776:
777: // ^reflection:delete[object or class;field_name]
778: add_native_method("delete", Method::CT_STATIC, _delete, 2, 2);
1.54 moko 779:
780: // ^reflection:mixin[object or class or junction;options]
1.55 moko 781: add_native_method("mixin", Method::CT_STATIC, _mixin, 1, 2);
1.54 moko 782:
1.99 ! moko 783: // ^reflection:override[method junction[;$.to[class] $.name[another_name]]]
! 784: add_native_method("override", Method::CT_STATIC, _override, 1, 2);
! 785:
1.78 moko 786: // ^reflection:tainting[[language or 'tainted' or 'optimized';]string]
1.76 moko 787: add_native_method("tainting", Method::CT_STATIC, _tainting, 1, 2);
788:
1.81 moko 789: // ^reflection:stack[options]
790: add_native_method("stack", Method::CT_STATIC, _stack, 0, 1);
791:
1.1 misha 792: }
E-mail: