Annotation of parser3/src/classes/reflection.C, revision 1.102
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.102 ! moko 14: volatile const char * IDENT_REFLECTION_C="$Id: reflection.C,v 1.101 2026/02/25 18:22:40 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.101 moko 129: for(OrderedHashString<VStateless_class*>::Iterator i(r.classes()); i; i.next()){
1.47 moko 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")) {
1.80 moko 478: for(HashStringValue::Iterator i(*options); i; i.next() ){
479: String::Body key=i.key();
480: Value* value=i.value();
481: if(key == "to") {
482: vtarget=value;
483: } else if(key == "name") {
484: name=&value->as_string();
485: } else if(key == "methods") {
486: copy_methods=r.process(*value).as_bool();
487: } else if(key == "fields") {
488: copy_fields=r.process(*value).as_bool();
489: } else if(key == "overwrite") {
490: overwrite=r.process(*value).as_bool();
1.100 moko 491: } else
492: throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION);
1.55 moko 493: }
494: }
495:
496: if(!vtarget)
497: vtarget=&r.get_method_frame()->caller()->self();
498:
499: VClass* source=dynamic_cast<VClass*>(vsource.get_class());
500: VClass* target=dynamic_cast<VClass*>(vtarget->get_class());
501:
502: if(!source)
503: throw Exception(PARSER_RUNTIME, 0, "source must be parser object or class");
504: if(!target)
505: throw Exception(PARSER_RUNTIME, 0, "destination must be parser object or class");
506:
507: if(name){
508: if(copy_methods)
509: if(Method* method=source->get_method(*name))
510: if(overwrite || !target->get_method(*name)){
1.59 moko 511: target->set_method(*name, new Method(*method));
1.55 moko 512: }
513:
514: if(copy_fields)
515: if(Property* property=source->get_properties()->get(*name))
516: if(property->value && (overwrite || !target->get_properties()->get(*name))){
517: target->put_element(*target, *name, property->value);
518: }
519:
520: } else {
521: if(copy_methods)
522: for(HashStringMethod::Iterator i(source->get_methods()); i; i.next()){
523: if(overwrite || !target->get_method(i.key()))
1.59 moko 524: target->set_method(*i.value()->name, new Method(*i.value()));
1.55 moko 525: }
526: if(copy_fields)
527: for(HashStringProperty::Iterator i(*source->get_properties()); i; i.next()){
528: if(i.value()->value && ( overwrite || !target->get_properties()->get(i.key()) ))
529: target->put_element(*target, *new String(i.key(), String::L_TAINTED), i.value()->value);
530: }
531: }
532: }
533:
1.99 moko 534: static void _override(Request& r, MethodParams& params) {
535: Junction *j=params[0].get_junction();
536: const Method* method=j ? j->method : 0;
537: if(!method)
538: throw Exception(PARSER_RUNTIME, 0, "param must be method junction");
1.102 ! moko 539: if(method->native_code)
! 540: throw Exception(PARSER_RUNTIME, 0, "param must not be native method");
1.99 moko 541:
542: const String *name=method->name;
543: Value* vtarget=0;
544: if(params.count()>1)
545: if(HashStringValue* options=params.as_hash(1, "override options")) {
546: for(HashStringValue::Iterator i(*options); i; i.next() ){
547: if(i.key() == "to") {
548: vtarget=i.value();
549: } else if(i.key() == "name") {
550: name=&i.value()->as_string();
1.100 moko 551: } else
552: throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION);
1.99 moko 553: }
554: }
555:
556: if(!vtarget)
557: vtarget=&r.get_method_frame()->caller()->self();
558:
559: VClass* target=dynamic_cast<VClass*>(vtarget->get_class());
560:
561: if(!target)
562: throw Exception(PARSER_RUNTIME, 0, "destination must be parser object or class");
563:
564: target->set_method(*name, new Method(*method));
565: }
566:
1.76 moko 567: String::Language get_untaint_lang(const String& lang_name); // op.C
568:
569: static void _tainting(Request& r, MethodParams& params) {
1.78 moko 570: const String& str=params.as_string(params.count()-1, "param must be string");
1.76 moko 571: String::Language lang = String::L_UNSPECIFIED;
572: bool optimized=false;
573:
574: if(params.count()==2){
1.78 moko 575: const String& slang=params.as_string(0, "language name must be string");
1.76 moko 576: if(slang == "optimized")
577: optimized=true;
578: else if(slang == "tainted")
579: lang=String::L_TAINTED;
580: else lang=get_untaint_lang(slang);
581: }
582:
583: if(!str.is_empty()){
584: char *visual=str.visualize_langs();
585:
586: if(optimized){
587: for(char *c=visual; *c; c++)
588: *c = *c<0 ? '+':'-';
589: } else if(lang != String::L_UNSPECIFIED){
590: for(char *c=visual; *c; c++)
591: *c = *c==lang ? '+':'-';
592: } else {
593: for(char *c=visual; *c; c++)
594: *c = *c & 0x7F;
595: }
596:
597: r.write(*new String(visual));
598: }
599: }
1.26 misha 600:
1.81 moko 601: static void _stack(Request& r, MethodParams& params) {
602: bool show_args=false;
603: bool show_locals=false;
604:
605: int limit=1000000;
606: int offset=0;
607:
608: if(params.count()>0)
609: if(HashStringValue* options=params.as_hash(0, "stack options")) {
610: for(HashStringValue::Iterator i(*options); i; i.next() ){
611: String::Body key=i.key();
612: Value* value=i.value();
613: if(key == "args") {
614: show_args=r.process(*value).as_bool();
1.82 moko 615: } else if(key == "locals") {
1.81 moko 616: show_locals=r.process(*value).as_bool();
1.82 moko 617: } else if(key == "limit") {
1.81 moko 618: limit=r.process(*value).as_int();
1.82 moko 619: } else if(key == "offset") {
1.81 moko 620: offset=r.process(*value).as_int();
1.100 moko 621: } else
622: throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION);
1.81 moko 623: }
624: }
625:
626: limit+=offset;
627:
628: VHash& vresult=*new VHash;
629: HashStringValue* result=vresult.get_hash();
630: int index=1;
631: VMethodFrame* caller=r.get_method_frame()->caller();
632: while(caller && index <= limit){
633: if(index>offset){
634: VHash& vcurrent=*new VHash;
635: HashStringValue* current=vcurrent.get_hash();
636:
637: current->put(Symbols::SELF_SYMBOL, &caller->self());
638:
639: const Method& method=caller->method;
640:
641: current->put(method_name, new VString(*method.name));
642:
643: if(!method.native_code){
644: Operation::Origin origin=r.get_method_origin(&method);
645: if(origin.file_no){
1.98 moko 646: HASH_PUT_CSTR(*current, "file", new VString(*r.get_used_filespec(origin.file_no)));
647: HASH_PUT_CSTR(*current, "line", new VInt(origin.line)); // no +1 as declaration before first command
1.81 moko 648: }
649:
650: if(show_args || show_locals){
651:
652: VHash& vargs=*new VHash;
653: HashStringValue* args=vargs.get_hash();
654:
655: if(method.params_names){
656: for(size_t i=0; i<method.params_names->count(); i++){
657: const String& pname=*(*method.params_names)[i];
658: Value* value=caller->get_element(pname);
659: args->put(pname, value->get_junction() ? VVoid::get() : value);
660: }
661: }
662: if(method.extra_params)
663: args->put(*method.extra_params, caller->get_element(*method.extra_params));
664:
665: if(show_args)
1.98 moko 666: HASH_PUT_CSTR(*current, "args", &vargs);
1.81 moko 667:
668: if(show_locals){
669: VHash& vlocals=*new VHash;
670: HashStringValue* locals=vlocals.get_hash();
671:
672: if(VParserMethodFrame* frame=dynamic_cast<VParserMethodFrame*>(caller))
673: for(HashString<Value*>::Iterator h(frame->my); h; h.next()){
674: String::Body key=h.key();
675: Value* value=h.value();
676: if(!args->contains(key) && (key != "result")){
677: locals->put(key, value->get_junction() ? VVoid::get() : value);
678: }
679: }
680:
1.98 moko 681: HASH_PUT_CSTR(*current, "locals", &vlocals);
1.81 moko 682: }
683: }
684: }
685:
1.98 moko 686: result->put(String::Body::uitoa(index), &vcurrent);
1.81 moko 687: }
688: caller=caller->caller();
689: index++;
690: }
691:
692: r.write(vresult);
693: }
694:
1.1 misha 695: // constructor
696: MReflection::MReflection(): Methoded("reflection") {
1.2 misha 697: // ^reflection:create[class_name;constructor_name[;param1[;param2[;...]]]]
1.73 moko 698: // ^reflection:create[ $.class[name] $.constructor[name] $.arguments[ $.1[param1] $.2[param2] ...] ]
699: add_native_method("create", Method::CT_STATIC, _create, 1, MAX_CREATE_PARAMS + 2);
1.1 misha 700:
1.3 misha 701: // ^reflection:classes[]
702: add_native_method("classes", Method::CT_STATIC, _classes, 0, 0);
703:
1.1 misha 704: // ^reflection:class[object]
705: add_native_method("class", Method::CT_STATIC, _class, 1, 1);
706:
707: // ^reflection:class_name[object]
708: add_native_method("class_name", Method::CT_STATIC, _class_name, 1, 1);
709:
1.34 moko 710: // ^reflection:class_by_name[class_name]
711: add_native_method("class_by_name", Method::CT_STATIC, _class_by_name, 1, 1);
712:
1.91 moko 713: // ^reflection:class_alias[class_name;new_class_name]
714: add_native_method("class_alias", Method::CT_STATIC, _class_alias, 2, 2);
715:
1.2 misha 716: // ^reflection:base_class[object]
717: add_native_method("base", Method::CT_STATIC, _base, 1, 1);
718:
719: // ^reflection:base_class_name[object]
720: add_native_method("base_name", Method::CT_STATIC, _base_name, 1, 1);
721:
1.30 misha 722: // ^reflection:def[class|...;name]
723: add_native_method("def", Method::CT_STATIC, _def, 2, 2);
724:
1.2 misha 725: // ^reflection:methods[class_name]
1.84 moko 726: add_native_method("methods", Method::CT_STATIC, _methods, 1, 2);
1.2 misha 727:
1.54 moko 728: // ^reflection:method[object or class;method_name[;self]]
729: // ^reflection:method[junction[;self]]
1.50 moko 730: add_native_method("method", Method::CT_STATIC, _method, 1, 3);
1.28 misha 731:
732: // ^reflection:method_info[class_name;method_name]
1.59 moko 733: // ^reflection:method_info[junction]
734: add_native_method("method_info", Method::CT_STATIC, _method_info, 1, 2);
1.28 misha 735:
1.79 moko 736: // ^reflection:filename[object or class or method]
1.67 moko 737: add_native_method("filename", Method::CT_STATIC, _filename, 1, 1);
738:
1.13 misha 739: // ^reflection:fields[object or class]
740: add_native_method("fields", Method::CT_STATIC, _fields, 1, 1);
741:
1.44 moko 742: // ^reflection:fields_reference[object]
743: add_native_method("fields_reference", Method::CT_STATIC, _fields_reference, 1, 1);
744:
1.28 misha 745: // ^reflection:field[object or class;field_name]
746: add_native_method("field", Method::CT_STATIC, _field, 2, 2);
1.9 misha 747:
748: // ^reflection:dynamical[[object or class, caller if absent]]
749: add_native_method("dynamical", Method::CT_STATIC, _dynamical, 0, 1);
1.19 moko 750:
1.39 moko 751: // ^reflection:is[element_name;class_name|code|method[;context]]
1.35 moko 752: add_native_method("is", Method::CT_STATIC, _is, 2, 3);
753:
1.19 moko 754: // ^reflection:copy[src;dst]
755: add_native_method("copy", Method::CT_STATIC, _copy, 2, 2);
1.25 moko 756:
757: // ^reflection:uid[object or class]
758: add_native_method("uid", Method::CT_STATIC, _uid, 1, 1);
1.26 misha 759:
760: // ^reflection:delete[object or class;field_name]
761: add_native_method("delete", Method::CT_STATIC, _delete, 2, 2);
1.54 moko 762:
763: // ^reflection:mixin[object or class or junction;options]
1.55 moko 764: add_native_method("mixin", Method::CT_STATIC, _mixin, 1, 2);
1.54 moko 765:
1.99 moko 766: // ^reflection:override[method junction[;$.to[class] $.name[another_name]]]
767: add_native_method("override", Method::CT_STATIC, _override, 1, 2);
768:
1.78 moko 769: // ^reflection:tainting[[language or 'tainted' or 'optimized';]string]
1.76 moko 770: add_native_method("tainting", Method::CT_STATIC, _tainting, 1, 2);
771:
1.81 moko 772: // ^reflection:stack[options]
773: add_native_method("stack", Method::CT_STATIC, _stack, 0, 1);
774:
1.1 misha 775: }
E-mail: