Annotation of parser3/src/classes/reflection.C, revision 1.22
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.22 ! moko 8: static const char * const IDENT_REFLECTION_C="$Date: 2010-10-09 23:17:26 $";
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: };
33:
34: // global variable
35:
36: DECLARE_CLASS_VAR(reflection, new MReflection, 0);
37:
38: // methods
39:
1.2 misha 40:
41: static void _create(Request& r, MethodParams& params) {
1.1 misha 42: const String& class_name=params.as_string(0, "class_name must be string");
1.11 misha 43: Value* class_value=r.get_class(class_name);
1.1 misha 44:
45: if(!class_value)
46: throw Exception(PARSER_RUNTIME,
47: &class_name,
48: "class is undefined");
49:
50: const String& constructor_name=params.as_string(1, "constructor_name must be string");
1.6 misha 51: Value* constructor_value=class_value->get_element(constructor_name);
1.1 misha 52:
1.10 misha 53: if(!constructor_value || !constructor_value->get_junction())
1.1 misha 54: throw Exception(PARSER_RUNTIME,
55: &constructor_name,
56: "constructor must be declared in class '%s'",
1.2 misha 57: class_value->get_class()->name_cstr());
1.1 misha 58:
59: Junction* junction=constructor_value->get_junction();
1.2 misha 60: const Method* method=junction->method;
61:
62: int nparams=params.count()-2;
63: int max_params_count;
64:
65: if(method->native_code){
66: if(method->call_type==Method::CT_STATIC)
67: throw Exception(PARSER_RUNTIME,
68: &constructor_name,
69: "native method of class '%s' (%s) is not allowed to be called dynamically",
70: class_value->get_class()->name_cstr(),
71: class_value->type());
72:
73: if(nparams<method->min_numbered_params_count)
74: throw Exception(PARSER_RUNTIME,
75: &constructor_name,
76: "native method of class '%s' (%s) accepts minimum %d parameter(s) (%d passed)",
77: class_value->get_class()->name_cstr(),
78: class_value->type(),
79: method->min_numbered_params_count,
80: nparams);
81:
82: max_params_count=method->max_numbered_params_count;
83: } else {
1.12 misha 84: max_params_count=method->params_names?method->params_names->count():0;
1.2 misha 85: }
86:
87: if(nparams>max_params_count)
88: throw Exception(PARSER_RUNTIME,
89: &constructor_name,
90: "method of class '%s' (%s) accepts maximum %d parameter(s) (%d passed)",
91: class_value->get_class()->name_cstr(),
92: class_value->type(),
93: max_params_count,
94: nparams);
1.1 misha 95:
1.17 moko 96: Value &object = r.construct(*class_value, *method);
97: VConstructorFrame frame(*method, r.get_method_frame(), object);
1.1 misha 98:
1.3 misha 99: Value* v[100];
1.1 misha 100: if(nparams>0){
1.2 misha 101: for(int i=0; i<nparams; i++)
1.1 misha 102: v[i]=&r.process_to_value(params[i+2]);
103: frame.store_params((Value**)&v, nparams);
104: } else {
105: frame.empty_params();
106: }
1.17 moko 107: r.op_call(frame);
1.18 moko 108: object.enable_default_setter();
1.21 moko 109: r.write_pass_lang(frame.result());
1.1 misha 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.16 misha 261: const String* filespec = r.get_method_filename(method);
262: if( filespec )
263: hash->put("file", new VString(*filespec));
1.2 misha 264: if(method->params_names)
265: for(size_t i=0; i<method->params_names->count(); i++)
266: hash->put(String::Body::Format(i), new VString(*method->params_names->get(i)));
267: }
268:
269: r.write_no_lang(result);
270: }
271:
1.9 misha 272: static void _dynamical(Request& r, MethodParams& params) {
273: if(params.count()){
274: r.write_no_lang(VBool::get(params[0].get_class() != ¶ms[0]));
275: } else {
276: VMethodFrame* caller=r.get_method_frame()->caller();
277: r.write_no_lang(VBool::get(caller && caller->get_class() != &caller->self()));
278: }
279: }
280:
1.19 moko 281: static void _copy(Request& r, MethodParams& params) {
282: HashStringValue* src=params.as_no_junction(0, "source must not be code").get_hash();
283:
284: if(src==NULL)
285: throw Exception(PARSER_RUNTIME, 0, "source must have hash representation");
286:
287: Value& dst=params.as_no_junction(1, "destination must not be code");
288:
289: for(HashStringValue::Iterator i(*src); i; i.next())
1.20 moko 290: r.put_element(dst, *new String(i.key(), String::L_TAINTED), i.value());
1.19 moko 291: }
292:
1.1 misha 293: // constructor
294: MReflection::MReflection(): Methoded("reflection") {
1.2 misha 295: // ^reflection:create[class_name;constructor_name[;param1[;param2[;...]]]]
296: add_native_method("create", Method::CT_STATIC, _create, 2, 102);
1.1 misha 297:
1.3 misha 298: // ^reflection:classes[]
299: add_native_method("classes", Method::CT_STATIC, _classes, 0, 0);
300:
1.1 misha 301: // ^reflection:class[object]
302: add_native_method("class", Method::CT_STATIC, _class, 1, 1);
303:
304: // ^reflection:class_name[object]
305: add_native_method("class_name", Method::CT_STATIC, _class_name, 1, 1);
306:
1.2 misha 307: // ^reflection:base_class[object]
308: add_native_method("base", Method::CT_STATIC, _base, 1, 1);
309:
310: // ^reflection:base_class_name[object]
311: add_native_method("base_name", Method::CT_STATIC, _base_name, 1, 1);
312:
313: // ^reflection:methods[class_name]
1.1 misha 314: add_native_method("methods", Method::CT_STATIC, _methods, 1, 1);
1.2 misha 315:
1.13 misha 316: // ^reflection:fields[object or class]
317: add_native_method("fields", Method::CT_STATIC, _fields, 1, 1);
318:
1.14 misha 319: // ^reflection:method_info[class_name;method_name]
1.8 misha 320: add_native_method("method_info", Method::CT_STATIC, _method_info, 2, 2);
1.9 misha 321:
322: // ^reflection:dynamical[[object or class, caller if absent]]
323: add_native_method("dynamical", Method::CT_STATIC, _dynamical, 0, 1);
1.19 moko 324:
325: // ^reflection:copy[src;dst]
326: add_native_method("copy", Method::CT_STATIC, _copy, 2, 2);
1.1 misha 327: }
E-mail: