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