Annotation of parser3/src/classes/reflection.C, revision 1.17
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.17 ! moko 8: static const char * const IDENT_REFLECTION_C="$Date: 2010-05-22 07:37:05 $";
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);
! 110: r.write_pass_lang(object);
1.1 misha 111: }
112:
1.2 misha 113:
1.3 misha 114: static void store_vlass_info(
115: HashStringValue::key_type key,
116: HashStringValue::value_type value,
117: HashStringValue* result
118: ){
119: Value* v;
120: if(value->get_class())
121: v=new VString(class_type_methoded);
122: else
123: v=VVoid::get();
124: result->put(key, v);
125: }
126:
127: static void _classes(Request& r, MethodParams&) {
128: VHash& result=*new VHash;
129: r.classes().for_each(store_vlass_info, result.get_hash());
130: r.write_no_lang(result);
131: }
132:
133:
134: static Value* get_class(Value* value){
135: if(VStateless_class* result=value->get_class())
136: return result;
137: else
138: // classes with fields only, like env & console
139: return value;
140: }
141:
142: static const String* get_class_name(Value* value){
143: if(VStateless_class* lclass=value->get_class())
144: return &lclass->name();
145: else
146: // classes with fields only, like env & console
147: return new String(value->type());
148: }
149:
150:
1.1 misha 151: static void _class(Request& r, MethodParams& params) {
1.3 misha 152: r.write_no_lang(*get_class(¶ms[0]));
1.1 misha 153: }
154:
1.2 misha 155:
1.1 misha 156: static void _class_name(Request& r, MethodParams& params) {
1.3 misha 157: r.write_no_lang(*get_class_name(¶ms[0]));
1.1 misha 158: }
159:
160:
1.2 misha 161: static void _base(Request& r, MethodParams& params) {
1.3 misha 162: if(VStateless_class* lclass=params[0].get_class())
163: if(Value* base=lclass->base()){
164: r.write_no_lang(*get_class(base));
165: return;
166: }
167:
168: // classes with fields only, like env & console or without base
169: r.write_no_lang(*VVoid::get());
1.2 misha 170: }
1.1 misha 171:
172:
1.2 misha 173: static void _base_name(Request& r, MethodParams& params) {
1.3 misha 174: if(VStateless_class* lclass=params[0].get_class())
1.2 misha 175: if(Value* base=lclass->base())
1.3 misha 176: r.write_no_lang(*get_class_name(base));
1.2 misha 177: }
1.1 misha 178:
1.2 misha 179: static void store_method_info(
1.7 misha 180: HashStringMethod::key_type key,
181: HashStringMethod::value_type method,
1.8 misha 182: HashStringValue* result
1.2 misha 183: ) {
1.8 misha 184: result->put(key, new VString(method->native_code?method_type_native:method_type_parser));
1.1 misha 185: }
186:
187: static void _methods(Request& r, MethodParams& params) {
188: const String& class_name=params.as_string(0, "class_name must be string");
1.11 misha 189: Value* class_value=r.get_class(class_name);
1.1 misha 190: if(!class_value)
191: throw Exception(PARSER_RUNTIME,
192: &class_name,
193: "class is undefined");
194:
195: VHash& result=*new VHash;
196: if(VStateless_class* lclass=class_value->get_class()){
1.7 misha 197: HashStringMethod methods=lclass->get_methods();
1.8 misha 198: methods.for_each(store_method_info, result.get_hash());
1.1 misha 199: } else {
1.3 misha 200: // class which does not have methods (env, console, etc)
1.1 misha 201: }
202: r.write_no_lang(result);
203: }
204:
1.13 misha 205: static void _fields(Request& r, MethodParams& params) {
206: if(HashStringValue* fields=params[0].get_fields()){
207: VHash& result=*new VHash(*fields);
208: r.write_no_lang(result);
209: } else
210: r.write_no_lang(*new VHash());
211: }
1.2 misha 212:
1.8 misha 213: static void _method_info(Request& r, MethodParams& params) {
1.2 misha 214: const String& class_name=params.as_string(0, "class_name must be string");
1.11 misha 215: Value* class_value=r.get_class(class_name);
1.2 misha 216: if(!class_value)
217: throw Exception(PARSER_RUNTIME,
218: &class_name,
219: "class is undefined");
220:
221: VStateless_class* lclass=class_value->get_class();
222: if(!lclass)
223: throw Exception(PARSER_RUNTIME,
224: &class_name,
225: "class does not have methods");
226:
227: const String& method_name=params.as_string(1, "method_name must be string");
228: Method* method=lclass->get_method(method_name);
229: if(!method)
230: throw Exception(PARSER_RUNTIME,
231: &method_name,
232: "method not found in class %s",
233: class_name.cstr());
234:
235: VHash& result=*new VHash;
236: HashStringValue* hash=result.get_hash();
1.8 misha 237:
238: VStateless_class* c=lclass;
1.9 misha 239: while(c->base() && c->base()->get_method(method_name))
1.8 misha 240: c=c->base()->get_class();
241:
242: if(c!=lclass)
243: hash->put(method_inherited, new VString(c->name()));
244:
1.2 misha 245: if(method->native_code){
246: // native code
247: hash->put(method_min_params, new VInt(method->min_numbered_params_count));
248: hash->put(method_max_params, new VInt(method->max_numbered_params_count));
1.5 misha 249: Value* call_type=0;
1.2 misha 250: switch(method->call_type){
251: case Method::CT_DYNAMIC:
1.4 misha 252: call_type=new VString(method_call_type_dynamic);
1.2 misha 253: break;
254: case Method::CT_STATIC:
1.4 misha 255: call_type=new VString(method_call_type_static);
1.2 misha 256: break;
257: }
1.5 misha 258: if(call_type)
259: hash->put(method_call_type, call_type);
1.2 misha 260: } else {
261: // parser code
1.16 misha 262: const String* filespec = r.get_method_filename(method);
263: if( filespec )
264: hash->put("file", new VString(*filespec));
1.2 misha 265: if(method->params_names)
266: for(size_t i=0; i<method->params_names->count(); i++)
267: hash->put(String::Body::Format(i), new VString(*method->params_names->get(i)));
268: }
269:
270: r.write_no_lang(result);
271: }
272:
1.9 misha 273: static void _dynamical(Request& r, MethodParams& params) {
274: if(params.count()){
275: r.write_no_lang(VBool::get(params[0].get_class() != ¶ms[0]));
276: } else {
277: VMethodFrame* caller=r.get_method_frame()->caller();
278: r.write_no_lang(VBool::get(caller && caller->get_class() != &caller->self()));
279: }
280: }
281:
1.1 misha 282: // constructor
283: MReflection::MReflection(): Methoded("reflection") {
1.2 misha 284: // ^reflection:create[class_name;constructor_name[;param1[;param2[;...]]]]
285: add_native_method("create", Method::CT_STATIC, _create, 2, 102);
1.1 misha 286:
1.3 misha 287: // ^reflection:classes[]
288: add_native_method("classes", Method::CT_STATIC, _classes, 0, 0);
289:
1.1 misha 290: // ^reflection:class[object]
291: add_native_method("class", Method::CT_STATIC, _class, 1, 1);
292:
293: // ^reflection:class_name[object]
294: add_native_method("class_name", Method::CT_STATIC, _class_name, 1, 1);
295:
1.2 misha 296: // ^reflection:base_class[object]
297: add_native_method("base", Method::CT_STATIC, _base, 1, 1);
298:
299: // ^reflection:base_class_name[object]
300: add_native_method("base_name", Method::CT_STATIC, _base_name, 1, 1);
301:
302: // ^reflection:methods[class_name]
1.1 misha 303: add_native_method("methods", Method::CT_STATIC, _methods, 1, 1);
1.2 misha 304:
1.13 misha 305: // ^reflection:fields[object or class]
306: add_native_method("fields", Method::CT_STATIC, _fields, 1, 1);
307:
1.14 misha 308: // ^reflection:method_info[class_name;method_name]
1.8 misha 309: add_native_method("method_info", Method::CT_STATIC, _method_info, 2, 2);
1.9 misha 310:
311: // ^reflection:dynamical[[object or class, caller if absent]]
312: add_native_method("dynamical", Method::CT_STATIC, _dynamical, 0, 1);
1.1 misha 313: }
E-mail: