Annotation of parser3/src/classes/reflection.C, revision 1.106
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.106 ! moko 15: volatile const char * IDENT_REFLECTION_C="$Id: reflection.C,v 1.105 2026/09/25 17:03:52 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];
457: int size=snprintf(local_buf, sizeof(local_buf), "%p", &obj);
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: 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.103 moko 610: struct LocalsInfo { HashStringValue* args; HashStringValue* locals; };
611:
612: static void collect_local(const String::Body& key, Value* value, LocalsInfo* info) {
613: if(!info->args->contains(key) && (key != "result"))
614: info->locals->put(key, value->get_junction() ? VVoid::get() : value);
615: }
616:
1.81 moko 617: static void _stack(Request& r, MethodParams& params) {
1.105 moko 618: if(params.count())
619: if(VException* exception=dynamic_cast<VException*>(¶ms[0])) {
620: r.write(*new VTable(&exception->stack(r)));
621: return;
622: }
623:
1.81 moko 624: bool show_args=false;
625: bool show_locals=false;
626:
627: int limit=1000000;
628: int offset=0;
629:
630: if(params.count()>0)
631: if(HashStringValue* options=params.as_hash(0, "stack options")) {
632: for(HashStringValue::Iterator i(*options); i; i.next() ){
633: String::Body key=i.key();
634: Value* value=i.value();
635: if(key == "args") {
636: show_args=r.process(*value).as_bool();
1.82 moko 637: } else if(key == "locals") {
1.81 moko 638: show_locals=r.process(*value).as_bool();
1.82 moko 639: } else if(key == "limit") {
1.81 moko 640: limit=r.process(*value).as_int();
1.82 moko 641: } else if(key == "offset") {
1.81 moko 642: offset=r.process(*value).as_int();
1.100 moko 643: } else
644: throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION);
1.81 moko 645: }
646: }
647:
648: limit+=offset;
649:
650: VHash& vresult=*new VHash;
651: HashStringValue* result=vresult.get_hash();
652: int index=1;
653: VMethodFrame* caller=r.get_method_frame()->caller();
654: while(caller && index <= limit){
655: if(index>offset){
656: VHash& vcurrent=*new VHash;
657: HashStringValue* current=vcurrent.get_hash();
658:
659: current->put(Symbols::SELF_SYMBOL, &caller->self());
660:
661: const Method& method=caller->method;
662:
663: current->put(method_name, new VString(*method.name));
664:
665: if(!method.native_code){
666: Operation::Origin origin=r.get_method_origin(&method);
667: if(origin.file_no){
1.98 moko 668: HASH_PUT_CSTR(*current, "file", new VString(*r.get_used_filespec(origin.file_no)));
669: HASH_PUT_CSTR(*current, "line", new VInt(origin.line)); // no +1 as declaration before first command
1.81 moko 670: }
671:
672: if(show_args || show_locals){
673:
674: VHash& vargs=*new VHash;
675: HashStringValue* args=vargs.get_hash();
676:
677: if(method.params_names){
678: for(size_t i=0; i<method.params_names->count(); i++){
679: const String& pname=*(*method.params_names)[i];
680: Value* value=caller->get_element(pname);
681: args->put(pname, value->get_junction() ? VVoid::get() : value);
682: }
683: }
684: if(method.extra_params)
685: args->put(*method.extra_params, caller->get_element(*method.extra_params));
686:
687: if(show_args)
1.98 moko 688: HASH_PUT_CSTR(*current, "args", &vargs);
1.81 moko 689:
690: if(show_locals){
691: VHash& vlocals=*new VHash;
692: HashStringValue* locals=vlocals.get_hash();
693:
1.103 moko 694: if(VParserMethodFrame* frame=dynamic_cast<VParserMethodFrame*>(caller)){
695: LocalsInfo linfo = { args, locals };
696: frame->my.for_each(collect_local, &linfo);
697: }
1.81 moko 698:
1.98 moko 699: HASH_PUT_CSTR(*current, "locals", &vlocals);
1.81 moko 700: }
701: }
702: }
703:
1.98 moko 704: result->put(String::Body::uitoa(index), &vcurrent);
1.81 moko 705: }
706: caller=caller->caller();
707: index++;
708: }
709:
710: r.write(vresult);
711: }
712:
1.1 misha 713: // constructor
714: MReflection::MReflection(): Methoded("reflection") {
1.2 misha 715: // ^reflection:create[class_name;constructor_name[;param1[;param2[;...]]]]
1.73 moko 716: // ^reflection:create[ $.class[name] $.constructor[name] $.arguments[ $.1[param1] $.2[param2] ...] ]
717: add_native_method("create", Method::CT_STATIC, _create, 1, MAX_CREATE_PARAMS + 2);
1.1 misha 718:
1.3 misha 719: // ^reflection:classes[]
720: add_native_method("classes", Method::CT_STATIC, _classes, 0, 0);
721:
1.1 misha 722: // ^reflection:class[object]
723: add_native_method("class", Method::CT_STATIC, _class, 1, 1);
724:
725: // ^reflection:class_name[object]
726: add_native_method("class_name", Method::CT_STATIC, _class_name, 1, 1);
727:
1.34 moko 728: // ^reflection:class_by_name[class_name]
729: add_native_method("class_by_name", Method::CT_STATIC, _class_by_name, 1, 1);
730:
1.91 moko 731: // ^reflection:class_alias[class_name;new_class_name]
732: add_native_method("class_alias", Method::CT_STATIC, _class_alias, 2, 2);
733:
1.2 misha 734: // ^reflection:base_class[object]
735: add_native_method("base", Method::CT_STATIC, _base, 1, 1);
736:
737: // ^reflection:base_class_name[object]
738: add_native_method("base_name", Method::CT_STATIC, _base_name, 1, 1);
739:
1.30 misha 740: // ^reflection:def[class|...;name]
741: add_native_method("def", Method::CT_STATIC, _def, 2, 2);
742:
1.2 misha 743: // ^reflection:methods[class_name]
1.84 moko 744: add_native_method("methods", Method::CT_STATIC, _methods, 1, 2);
1.2 misha 745:
1.54 moko 746: // ^reflection:method[object or class;method_name[;self]]
747: // ^reflection:method[junction[;self]]
1.50 moko 748: add_native_method("method", Method::CT_STATIC, _method, 1, 3);
1.28 misha 749:
750: // ^reflection:method_info[class_name;method_name]
1.59 moko 751: // ^reflection:method_info[junction]
752: add_native_method("method_info", Method::CT_STATIC, _method_info, 1, 2);
1.28 misha 753:
1.79 moko 754: // ^reflection:filename[object or class or method]
1.67 moko 755: add_native_method("filename", Method::CT_STATIC, _filename, 1, 1);
756:
1.106 ! moko 757: // ^reflection:used[]
! 758: add_native_method("used", Method::CT_STATIC, _used, 0, 0);
! 759:
1.13 misha 760: // ^reflection:fields[object or class]
761: add_native_method("fields", Method::CT_STATIC, _fields, 1, 1);
762:
1.44 moko 763: // ^reflection:fields_reference[object]
764: add_native_method("fields_reference", Method::CT_STATIC, _fields_reference, 1, 1);
765:
1.28 misha 766: // ^reflection:field[object or class;field_name]
767: add_native_method("field", Method::CT_STATIC, _field, 2, 2);
1.9 misha 768:
769: // ^reflection:dynamical[[object or class, caller if absent]]
770: add_native_method("dynamical", Method::CT_STATIC, _dynamical, 0, 1);
1.19 moko 771:
1.39 moko 772: // ^reflection:is[element_name;class_name|code|method[;context]]
1.35 moko 773: add_native_method("is", Method::CT_STATIC, _is, 2, 3);
774:
1.19 moko 775: // ^reflection:copy[src;dst]
776: add_native_method("copy", Method::CT_STATIC, _copy, 2, 2);
1.25 moko 777:
778: // ^reflection:uid[object or class]
779: add_native_method("uid", Method::CT_STATIC, _uid, 1, 1);
1.26 misha 780:
781: // ^reflection:delete[object or class;field_name]
782: add_native_method("delete", Method::CT_STATIC, _delete, 2, 2);
1.54 moko 783:
784: // ^reflection:mixin[object or class or junction;options]
1.55 moko 785: add_native_method("mixin", Method::CT_STATIC, _mixin, 1, 2);
1.54 moko 786:
1.99 moko 787: // ^reflection:override[method junction[;$.to[class] $.name[another_name]]]
788: add_native_method("override", Method::CT_STATIC, _override, 1, 2);
789:
1.78 moko 790: // ^reflection:tainting[[language or 'tainted' or 'optimized';]string]
1.76 moko 791: add_native_method("tainting", Method::CT_STATIC, _tainting, 1, 2);
792:
1.81 moko 793: // ^reflection:stack[options]
794: add_native_method("stack", Method::CT_STATIC, _stack, 0, 1);
795:
1.1 misha 796: }
E-mail: