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