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: