Annotation of parser3/src/classes/reflection.C, revision 1.2
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.2 ! misha 8: static const char * const IDENT_REFLECTION_C="$Date: 2009-07-24 09:29:29 $";
1.1 misha 9:
10: #include "pa_vmethod_frame.h"
11: #include "pa_request.h"
12: #include "pa_vbool.h"
13:
1.2 ! misha 14: const char* const METHOD_TYPE_NATIVE="native";
! 15: const char* const METHOD_TYPE_PARSER="parser";
! 16:
! 17: const char* const METHOD_CALL_TYPE_STATIC="static";
! 18: const char* const METHOD_CALL_TYPE_DYNAMIC="dynamic";
! 19: const char* const METHOD_CALL_TYPE_ANY="any";
! 20:
! 21: const char* const METHOD_MIN_PARAMS="min_params";
! 22: const char* const METHOD_MAX_PARAMS="max_params";
! 23:
! 24: static const String method_type_native(METHOD_TYPE_NATIVE);
! 25: static const String method_type_parser(METHOD_TYPE_PARSER);
! 26:
! 27: static const String method_call_type_static(METHOD_CALL_TYPE_STATIC);
! 28: static const String method_call_type_dynamic(METHOD_CALL_TYPE_DYNAMIC);
! 29: static const String method_call_type_any(METHOD_CALL_TYPE_ANY);
! 30:
! 31: static const String method_min_params(METHOD_MIN_PARAMS);
! 32: static const String method_max_params(METHOD_MAX_PARAMS);
! 33:
1.1 misha 34: // class
35:
36: class MReflection: public Methoded {
37: public:
38: MReflection();
39: public: // Methoded
40: bool used_directly() { return true; }
41: };
42:
43: // global variable
44:
45: DECLARE_CLASS_VAR(reflection, new MReflection, 0);
46:
47: // methods
48:
1.2 ! misha 49:
! 50: static void _create(Request& r, MethodParams& params) {
1.1 misha 51: const String& class_name=params.as_string(0, "class_name must be string");
52: Value* class_value=r.classes().get(class_name);
53:
54: if(!class_value)
55: throw Exception(PARSER_RUNTIME,
56: &class_name,
57: "class is undefined");
58:
59: const String& constructor_name=params.as_string(1, "constructor_name must be string");
60: Value* constructor_value=class_value->get_element(constructor_name, *class_value, true);
61:
1.2 ! misha 62: if(!constructor_value || !constructor_value->get_junction() || constructor_value->get_junction()->self.get_class()!=class_value)
1.1 misha 63: throw Exception(PARSER_RUNTIME,
64: &constructor_name,
65: "constructor must be declared in class '%s'",
1.2 ! misha 66: class_value->get_class()->name_cstr());
1.1 misha 67:
68: Junction* junction=constructor_value->get_junction();
1.2 ! misha 69: const Method* method=junction->method;
! 70:
! 71: int nparams=params.count()-2;
! 72: int max_params_count;
! 73:
! 74: if(method->native_code){
! 75: if(method->call_type==Method::CT_STATIC)
! 76: throw Exception(PARSER_RUNTIME,
! 77: &constructor_name,
! 78: "native method of class '%s' (%s) is not allowed to be called dynamically",
! 79: class_value->get_class()->name_cstr(),
! 80: class_value->type());
! 81:
! 82: if(nparams<method->min_numbered_params_count)
! 83: throw Exception(PARSER_RUNTIME,
! 84: &constructor_name,
! 85: "native method of class '%s' (%s) accepts minimum %d parameter(s) (%d passed)",
! 86: class_value->get_class()->name_cstr(),
! 87: class_value->type(),
! 88: method->min_numbered_params_count,
! 89: nparams);
! 90:
! 91: max_params_count=method->max_numbered_params_count;
! 92: } else {
! 93: max_params_count=method->params_names->count();
! 94: }
! 95:
! 96: if(nparams>max_params_count)
! 97: throw Exception(PARSER_RUNTIME,
! 98: &constructor_name,
! 99: "method of class '%s' (%s) accepts maximum %d parameter(s) (%d passed)",
! 100: class_value->get_class()->name_cstr(),
! 101: class_value->type(),
! 102: max_params_count,
! 103: nparams);
1.1 misha 104:
105: VMethodFrame frame(*junction, r.get_method_frame());
106:
107: Value* v[100];
108: if(nparams>0){
1.2 ! misha 109: for(int i=0; i<nparams; i++)
1.1 misha 110: v[i]=&r.process_to_value(params[i+2]);
111: frame.store_params((Value**)&v, nparams);
112: } else {
113: frame.empty_params();
114: }
115: r.op_call(frame, true/*constructing*/);
116: r.write_pass_lang(frame.result());
117: }
118:
1.2 ! misha 119:
! 120: // @todo: something wring with native classes (it returns stateless_class)
1.1 misha 121: static void _class(Request& r, MethodParams& params) {
1.2 ! misha 122: if(Value* lclass=params[0].get_last_derived_class())
1.1 misha 123: r.write_no_lang(*lclass);
124: else
125: throw Exception(PARSER_RUNTIME,
126: 0,
1.2 ! misha 127: "class is undefined");
1.1 misha 128: }
129:
1.2 ! misha 130:
1.1 misha 131: static void _class_name(Request& r, MethodParams& params) {
132: r.write_no_lang(String(params[0].type()));
133: }
134:
135:
1.2 ! misha 136: static void _base(Request& r, MethodParams& params) {
! 137: if(Value* lclass=params[0].get_class())
! 138: if(Value* base=lclass->base())
! 139: r.write_no_lang(*lclass->base());
! 140: else
! 141: r.write_no_lang(*VVoid::get());
! 142: else
! 143: throw Exception(PARSER_RUNTIME,
! 144: 0,
! 145: "class is undefined");
! 146: }
1.1 misha 147:
148:
1.2 ! misha 149: static void _base_name(Request& r, MethodParams& params) {
! 150: if(Value* lclass=params[0].get_class())
! 151: if(Value* base=lclass->base())
! 152: r.write_no_lang(String(base->type()));
! 153: }
1.1 misha 154:
155:
1.2 ! misha 156: static void store_method_info(
! 157: HashString<Method*>::key_type key,
! 158: HashString<Method*>::value_type method,
! 159: HashStringValue* result
! 160: ) {
! 161: result->put(key, new VString(method->native_code?method_type_native:method_type_parser));
1.1 misha 162: }
163:
164: static void _methods(Request& r, MethodParams& params) {
165: const String& class_name=params.as_string(0, "class_name must be string");
166: Value* class_value=r.classes().get(class_name);
167: if(!class_value)
168: throw Exception(PARSER_RUNTIME,
169: &class_name,
170: "class is undefined");
171:
172: VHash& result=*new VHash;
173: if(VStateless_class* lclass=class_value->get_class()){
174: HashString<Method*> methods=lclass->get_methods();
175: methods.for_each(store_method_info, result.get_hash());
1.2 ! misha 176: /*
1.1 misha 177: } else {
178: // exception?
1.2 ! misha 179: throw Exception(PARSER_RUNTIME,
! 180: &class_name,
! 181: "class does not have methods");
! 182: */
1.1 misha 183: }
184: r.write_no_lang(result);
185: }
186:
1.2 ! misha 187:
! 188: static void _method_params(Request& r, MethodParams& params) {
! 189: const String& class_name=params.as_string(0, "class_name must be string");
! 190: Value* class_value=r.classes().get(class_name);
! 191: if(!class_value)
! 192: throw Exception(PARSER_RUNTIME,
! 193: &class_name,
! 194: "class is undefined");
! 195:
! 196: VStateless_class* lclass=class_value->get_class();
! 197: if(!lclass)
! 198: throw Exception(PARSER_RUNTIME,
! 199: &class_name,
! 200: "class does not have methods");
! 201:
! 202:
! 203: const String& method_name=params.as_string(1, "method_name must be string");
! 204: Method* method=lclass->get_method(method_name);
! 205: if(!method)
! 206: throw Exception(PARSER_RUNTIME,
! 207: &method_name,
! 208: "method not found in class %s",
! 209: class_name.cstr());
! 210:
! 211: VHash& result=*new VHash;
! 212: HashStringValue* hash=result.get_hash();
! 213: if(method->native_code){
! 214: // native code
! 215: hash->put(method_min_params, new VInt(method->min_numbered_params_count));
! 216: hash->put(method_max_params, new VInt(method->max_numbered_params_count));
! 217: const String* call_type;
! 218: switch(method->call_type){
! 219: case Method::CT_DYNAMIC:
! 220: call_type=&method_call_type_dynamic;
! 221: break;
! 222: case Method::CT_STATIC:
! 223: call_type=&method_call_type_static;
! 224: break;
! 225: default:
! 226: call_type=&method_call_type_any;
! 227: }
! 228: hash->put(String("call_type"), new VString(*call_type));
! 229:
! 230: } else {
! 231: // parser code
! 232: if(method->params_names)
! 233: for(size_t i=0; i<method->params_names->count(); i++)
! 234: hash->put(String::Body::Format(i), new VString(*method->params_names->get(i)));
! 235: }
! 236:
! 237: r.write_no_lang(result);
! 238: }
! 239:
1.1 misha 240: // constructor
241: MReflection::MReflection(): Methoded("reflection") {
1.2 ! misha 242: // ^reflection:create[class_name;constructor_name[;param1[;param2[;...]]]]
! 243: add_native_method("create", Method::CT_STATIC, _create, 2, 102);
1.1 misha 244:
245: // ^reflection:class[object]
246: add_native_method("class", Method::CT_STATIC, _class, 1, 1);
247:
248: // ^reflection:class_name[object]
249: add_native_method("class_name", Method::CT_STATIC, _class_name, 1, 1);
250:
1.2 ! misha 251: // ^reflection:base_class[object]
! 252: add_native_method("base", Method::CT_STATIC, _base, 1, 1);
! 253:
! 254: // ^reflection:base_class_name[object]
! 255: add_native_method("base_name", Method::CT_STATIC, _base_name, 1, 1);
! 256:
! 257: // ^reflection:methods[class_name]
1.1 misha 258: add_native_method("methods", Method::CT_STATIC, _methods, 1, 1);
1.2 ! misha 259:
! 260: // ^reflection:method_params[class_name;method_name]
! 261: add_native_method("method_params", Method::CT_STATIC, _method_params, 2, 2);
! 262:
! 263: // @todo: check how 'create' and 'methods' work with ancestors-classes
1.1 misha 264: }
E-mail: