Annotation of parser3/src/classes/reflection.C, revision 1.19
1.1 misha 1: /** @file
2: Parser: @b reflection parser class.
3:
4: Copyright (c) 2001-2009 ArtLebedev Group (http://www.artlebedev.com)
5: Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
6: */
7:
1.19 ! moko 8: static const char * const IDENT_REFLECTION_C="$Date: 2010-08-11 16:21:51 $";
1.1 misha 9:
10: #include "pa_vmethod_frame.h"
11: #include "pa_request.h"
12: #include "pa_vbool.h"
13:
1.3 misha 14: static const String class_type_methoded("methoded");
1.2 misha 15:
1.3 misha 16: static const String method_type_native("native");
17: static const String method_type_parser("parser");
1.2 misha 18:
1.5 misha 19: static const String method_call_type("call_type");
1.8 misha 20: static const String method_inherited("inherited");
1.3 misha 21: static const String method_call_type_static("static");
22: static const String method_call_type_dynamic("dynamic");
1.2 misha 23:
1.3 misha 24: static const String method_min_params("min_params");
25: static const String method_max_params("max_params");
1.2 misha 26:
1.1 misha 27: // class
28:
29: class MReflection: public Methoded {
30: public:
31: MReflection();
32: public: // Methoded
33: bool used_directly() { return true; }
34: };
35:
36: // global variable
37:
38: DECLARE_CLASS_VAR(reflection, new MReflection, 0);
39:
40: // methods
41:
1.2 misha 42:
43: static void _create(Request& r, MethodParams& params) {
1.1 misha 44: const String& class_name=params.as_string(0, "class_name must be string");
1.11 misha 45: Value* class_value=r.get_class(class_name);
1.1 misha 46:
47: if(!class_value)
48: throw Exception(PARSER_RUNTIME,
49: &class_name,
50: "class is undefined");
51:
52: const String& constructor_name=params.as_string(1, "constructor_name must be string");
1.6 misha 53: Value* constructor_value=class_value->get_element(constructor_name);
1.1 misha 54:
1.10 misha 55: if(!constructor_value || !constructor_value->get_junction())
1.1 misha 56: throw Exception(PARSER_RUNTIME,
57: &constructor_name,
58: "constructor must be declared in class '%s'",
1.2 misha 59: class_value->get_class()->name_cstr());
1.1 misha 60:
61: Junction* junction=constructor_value->get_junction();
1.2 misha 62: const Method* method=junction->method;
63:
64: int nparams=params.count()-2;
65: int max_params_count;
66:
67: if(method->native_code){
68: if(method->call_type==Method::CT_STATIC)
69: throw Exception(PARSER_RUNTIME,
70: &constructor_name,
71: "native method of class '%s' (%s) is not allowed to be called dynamically",
72: class_value->get_class()->name_cstr(),
73: class_value->type());
74:
75: if(nparams<method->min_numbered_params_count)
76: throw Exception(PARSER_RUNTIME,
77: &constructor_name,
78: "native method of class '%s' (%s) accepts minimum %d parameter(s) (%d passed)",
79: class_value->get_class()->name_cstr(),
80: class_value->type(),
81: method->min_numbered_params_count,
82: nparams);
83:
84: max_params_count=method->max_numbered_params_count;
85: } else {
1.12 misha 86: max_params_count=method->params_names?method->params_names->count():0;
1.2 misha 87: }
88:
89: if(nparams>max_params_count)
90: throw Exception(PARSER_RUNTIME,
91: &constructor_name,
92: "method of class '%s' (%s) accepts maximum %d parameter(s) (%d passed)",
93: class_value->get_class()->name_cstr(),
94: class_value->type(),
95: max_params_count,
96: nparams);
1.1 misha 97:
1.17 moko 98: Value &object = r.construct(*class_value, *method);
99: VConstructorFrame frame(*method, r.get_method_frame(), object);
1.1 misha 100:
1.3 misha 101: Value* v[100];
1.1 misha 102: if(nparams>0){
1.2 misha 103: for(int i=0; i<nparams; i++)
1.1 misha 104: v[i]=&r.process_to_value(params[i+2]);
105: frame.store_params((Value**)&v, nparams);
106: } else {
107: frame.empty_params();
108: }
1.17 moko 109: r.op_call(frame);
1.18 moko 110: object.enable_default_setter();
1.17 moko 111: r.write_pass_lang(object);
1.1 misha 112: }
113:
1.2 misha 114:
1.3 misha 115: static void store_vlass_info(
116: HashStringValue::key_type key,
117: HashStringValue::value_type value,
118: HashStringValue* result
119: ){
120: Value* v;
121: if(value->get_class())
122: v=new VString(class_type_methoded);
123: else
124: v=VVoid::get();
125: result->put(key, v);
126: }
127:
128: static void _classes(Request& r, MethodParams&) {
129: VHash& result=*new VHash;
130: r.classes().for_each(store_vlass_info, result.get_hash());
131: r.write_no_lang(result);
132: }
133:
134:
135: static Value* get_class(Value* value){
136: if(VStateless_class* result=value->get_class())
137: return result;
138: else
139: // classes with fields only, like env & console
140: return value;
141: }
142:
143: static const String* get_class_name(Value* value){
144: if(VStateless_class* lclass=value->get_class())
145: return &lclass->name();
146: else
147: // classes with fields only, like env & console
148: return new String(value->type());
149: }
150:
151:
1.1 misha 152: static void _class(Request& r, MethodParams& params) {
1.3 misha 153: r.write_no_lang(*get_class(¶ms[0]));
1.1 misha 154: }
155:
1.2 misha 156:
1.1 misha 157: static void _class_name(Request& r, MethodParams& params) {
1.3 misha 158: r.write_no_lang(*get_class_name(¶ms[0]));
1.1 misha 159: }
160:
161:
1.2 misha 162: static void _base(Request& r, MethodParams& params) {
1.3 misha 163: if(VStateless_class* lclass=params[0].get_class())
164: if(Value* base=lclass->base()){
165: r.write_no_lang(*get_class(base));
166: return;
167: }
168:
169: // classes with fields only, like env & console or without base
170: r.write_no_lang(*VVoid::get());
1.2 misha 171: }
1.1 misha 172:
173:
1.2 misha 174: static void _base_name(Request& r, MethodParams& params) {
1.3 misha 175: if(VStateless_class* lclass=params[0].get_class())
1.2 misha 176: if(Value* base=lclass->base())
1.3 misha 177: r.write_no_lang(*get_class_name(base));
1.2 misha 178: }
1.1 misha 179:
1.2 misha 180: static void store_method_info(
1.7 misha 181: HashStringMethod::key_type key,
182: HashStringMethod::value_type method,
1.8 misha 183: HashStringValue* result
1.2 misha 184: ) {
1.8 misha 185: result->put(key, new VString(method->native_code?method_type_native:method_type_parser));
1.1 misha 186: }
187:
188: static void _methods(Request& r, MethodParams& params) {
189: const String& class_name=params.as_string(0, "class_name must be string");
1.11 misha 190: Value* class_value=r.get_class(class_name);
1.1 misha 191: if(!class_value)
192: throw Exception(PARSER_RUNTIME,
193: &class_name,
194: "class is undefined");
195:
196: VHash& result=*new VHash;
197: if(VStateless_class* lclass=class_value->get_class()){
1.7 misha 198: HashStringMethod methods=lclass->get_methods();
1.8 misha 199: methods.for_each(store_method_info, result.get_hash());
1.1 misha 200: } else {
1.3 misha 201: // class which does not have methods (env, console, etc)
1.1 misha 202: }
203: r.write_no_lang(result);
204: }
205:
1.13 misha 206: static void _fields(Request& r, MethodParams& params) {
207: if(HashStringValue* fields=params[0].get_fields()){
208: VHash& result=*new VHash(*fields);
209: r.write_no_lang(result);
210: } else
211: r.write_no_lang(*new VHash());
212: }
1.2 misha 213:
1.8 misha 214: static void _method_info(Request& r, MethodParams& params) {
1.2 misha 215: const String& class_name=params.as_string(0, "class_name must be string");
1.11 misha 216: Value* class_value=r.get_class(class_name);
1.2 misha 217: if(!class_value)
218: throw Exception(PARSER_RUNTIME,
219: &class_name,
220: "class is undefined");
221:
222: VStateless_class* lclass=class_value->get_class();
223: if(!lclass)
224: throw Exception(PARSER_RUNTIME,
225: &class_name,
226: "class does not have methods");
227:
228: const String& method_name=params.as_string(1, "method_name must be string");
229: Method* method=lclass->get_method(method_name);
230: if(!method)
231: throw Exception(PARSER_RUNTIME,
232: &method_name,
233: "method not found in class %s",
234: class_name.cstr());
235:
236: VHash& result=*new VHash;
237: HashStringValue* hash=result.get_hash();
1.8 misha 238:
239: VStateless_class* c=lclass;
1.9 misha 240: while(c->base() && c->base()->get_method(method_name))
1.8 misha 241: c=c->base()->get_class();
242:
243: if(c!=lclass)
244: hash->put(method_inherited, new VString(c->name()));
245:
1.2 misha 246: if(method->native_code){
247: // native code
248: hash->put(method_min_params, new VInt(method->min_numbered_params_count));
249: hash->put(method_max_params, new VInt(method->max_numbered_params_count));
1.5 misha 250: Value* call_type=0;
1.2 misha 251: switch(method->call_type){
252: case Method::CT_DYNAMIC:
1.4 misha 253: call_type=new VString(method_call_type_dynamic);
1.2 misha 254: break;
255: case Method::CT_STATIC:
1.4 misha 256: call_type=new VString(method_call_type_static);
1.2 misha 257: break;
258: }
1.5 misha 259: if(call_type)
260: hash->put(method_call_type, call_type);
1.2 misha 261: } else {
262: // parser code
1.16 misha 263: const String* filespec = r.get_method_filename(method);
264: if( filespec )
265: hash->put("file", new VString(*filespec));
1.2 misha 266: if(method->params_names)
267: for(size_t i=0; i<method->params_names->count(); i++)
268: hash->put(String::Body::Format(i), new VString(*method->params_names->get(i)));
269: }
270:
271: r.write_no_lang(result);
272: }
273:
1.9 misha 274: static void _dynamical(Request& r, MethodParams& params) {
275: if(params.count()){
276: r.write_no_lang(VBool::get(params[0].get_class() != ¶ms[0]));
277: } else {
278: VMethodFrame* caller=r.get_method_frame()->caller();
279: r.write_no_lang(VBool::get(caller && caller->get_class() != &caller->self()));
280: }
281: }
282:
1.19 ! moko 283: static void _copy(Request& r, MethodParams& params) {
! 284: HashStringValue* src=params.as_no_junction(0, "source must not be code").get_hash();
! 285:
! 286: if(src==NULL)
! 287: throw Exception(PARSER_RUNTIME, 0, "source must have hash representation");
! 288:
! 289: Value& dst=params.as_no_junction(1, "destination must not be code");
! 290:
! 291: for(HashStringValue::Iterator i(*src); i; i.next())
! 292: r.put_element(dst, String(i.key(), String::L_TAINTED), i.value());
! 293: }
! 294:
1.1 misha 295: // constructor
296: MReflection::MReflection(): Methoded("reflection") {
1.2 misha 297: // ^reflection:create[class_name;constructor_name[;param1[;param2[;...]]]]
298: add_native_method("create", Method::CT_STATIC, _create, 2, 102);
1.1 misha 299:
1.3 misha 300: // ^reflection:classes[]
301: add_native_method("classes", Method::CT_STATIC, _classes, 0, 0);
302:
1.1 misha 303: // ^reflection:class[object]
304: add_native_method("class", Method::CT_STATIC, _class, 1, 1);
305:
306: // ^reflection:class_name[object]
307: add_native_method("class_name", Method::CT_STATIC, _class_name, 1, 1);
308:
1.2 misha 309: // ^reflection:base_class[object]
310: add_native_method("base", Method::CT_STATIC, _base, 1, 1);
311:
312: // ^reflection:base_class_name[object]
313: add_native_method("base_name", Method::CT_STATIC, _base_name, 1, 1);
314:
315: // ^reflection:methods[class_name]
1.1 misha 316: add_native_method("methods", Method::CT_STATIC, _methods, 1, 1);
1.2 misha 317:
1.13 misha 318: // ^reflection:fields[object or class]
319: add_native_method("fields", Method::CT_STATIC, _fields, 1, 1);
320:
1.14 misha 321: // ^reflection:method_info[class_name;method_name]
1.8 misha 322: add_native_method("method_info", Method::CT_STATIC, _method_info, 2, 2);
1.9 misha 323:
324: // ^reflection:dynamical[[object or class, caller if absent]]
325: add_native_method("dynamical", Method::CT_STATIC, _dynamical, 0, 1);
1.19 ! moko 326:
! 327: // ^reflection:copy[src;dst]
! 328: add_native_method("copy", Method::CT_STATIC, _copy, 2, 2);
1.1 misha 329: }
E-mail: