--- parser3/src/classes/reflection.C 2016/11/27 23:08:28 1.68 +++ parser3/src/classes/reflection.C 2016/12/01 23:42:35 1.73 @@ -10,7 +10,7 @@ #include "pa_vbool.h" #include "pa_vobject.h" -volatile const char * IDENT_REFLECTION_C="$Id: reflection.C,v 1.68 2016/11/27 23:08:28 moko Exp $"; +volatile const char * IDENT_REFLECTION_C="$Id: reflection.C,v 1.73 2016/12/01 23:42:35 moko Exp $"; static const String class_type_methoded("methoded"); @@ -18,6 +18,7 @@ static const String method_type_native(" static const String method_type_parser("parser"); static const String method_name("name"); +static const String method_class_name("class"); static const String method_call_type("call_type"); static const String method_inherited("inherited"); static const String method_overridden("overridden"); @@ -41,61 +42,76 @@ DECLARE_CLASS_VAR(reflection, new MRefle // methods +const int MAX_CREATE_PARAMS = 100; static void _create(Request& r, MethodParams& params) { - const String& class_name=params.as_string(0, "class_name must be string"); - VStateless_class* vclass=r.get_class(class_name); + int params_offset; + HashStringValue* params_hash=0; - if(!vclass) - throw Exception(PARSER_RUNTIME, &class_name, "class is undefined"); + const String* class_name=0; + const String* constructor_name=0; - const String& constructor_name=params.as_string(1, "constructor_name must be string"); - Value* constructor_value=vclass->get_element(constructor_name); + Value& voptions=params.as_no_junction(0, "params must not be code"); + if(HashStringValue* options=voptions.get_hash()) { + int valid_options=0; + if(Value* vclass_name=options->get("class")) { + valid_options++; + class_name=&vclass_name->as_string(); + } + if(Value* vconstructor_name=options->get("constructor")) { + valid_options++; + constructor_name=&vconstructor_name->as_string(); + } + if(Value* vparams_hash=options->get("arguments")) { + valid_options++; + params_hash=vparams_hash->as_hash("arguments"); + if(params.count()>1) + throw Exception(PARSER_RUNTIME, 0, "agruments should not be specified as hash and as create params"); + } + if(valid_options!=options->count()) + throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION); - if(!constructor_value || !constructor_value->get_junction()) - throw Exception(PARSER_RUNTIME, &constructor_name, "constructor must be declared in class '%s'", vclass->type()); + if(!class_name) + throw Exception(PARSER_RUNTIME, 0, "class name must be specified"); + if(!constructor_name) + throw Exception(PARSER_RUNTIME, 0, "constructor name must be specified"); - Junction* junction=constructor_value->get_junction(); - const Method* method=junction->method; + params_offset=1; + } else { + class_name=¶ms.as_string(0, "param must be string or hash"); - int nparams=params.count()-2; - int max_params_count; + if(params.count()==1) + throw Exception(PARSER_RUNTIME, 0, "constructor name must be specified"); - if(method->native_code){ - if(method->call_type==Method::CT_STATIC) - throw Exception(PARSER_RUNTIME, - &constructor_name, - "native method of class '%s' is not allowed to be called dynamically", - vclass->type()); - - if(nparamsmin_numbered_params_count) - throw Exception(PARSER_RUNTIME, - &constructor_name, - "native method of class '%s' accepts minimum %d parameter(s) (%d passed)", - vclass->type(), - method->min_numbered_params_count, - nparams); + constructor_name=¶ms.as_string(1, "constructor name must be string"); - max_params_count=method->max_numbered_params_count; - } else { - max_params_count=method->params_count; + params_offset=2; } - if(nparams>max_params_count) - throw Exception(PARSER_RUNTIME, - &constructor_name, - "method of class '%s' accepts maximum %d parameter(s) (%d passed)", - vclass->type(), - max_params_count, - nparams); + VStateless_class* vclass=r.get_class(*class_name); + if(!vclass) + throw Exception(PARSER_RUNTIME, class_name, "class is undefined"); + + const Method* method=vclass->get_method(*constructor_name); + if(!method) + throw Exception(PARSER_RUNTIME, constructor_name, "constructor not found in class '%s'", vclass->type()); Value &object = r.construct(*vclass, *method); + int nparams=params_hash ? params_hash->count() : (params.count()-params_offset); + if(nparams>MAX_CREATE_PARAMS) + throw Exception(PARSER_RUNTIME, 0, "arguments count should not exceed %d", MAX_CREATE_PARAMS); + CONSTRUCTOR_FRAME_ACTION(*method, r.get_method_frame(), object, { - Value* v[100]; + Value* v[MAX_CREATE_PARAMS]; if(nparams>0){ - for(int i=0; iput(method_name, new VString(*method->name)); + hash->put(method_class_name, new VString(*new String(j->self.type()))); + } else { const String& class_name=params.as_string(0, "param must be class name or method junction"); VStateless_class* vclass=r.get_class(class_name); @@ -482,7 +500,8 @@ static void _mixin(Request& r, MethodPar // constructor MReflection::MReflection(): Methoded("reflection") { // ^reflection:create[class_name;constructor_name[;param1[;param2[;...]]]] - add_native_method("create", Method::CT_STATIC, _create, 2, 102); + // ^reflection:create[ $.class[name] $.constructor[name] $.arguments[ $.1[param1] $.2[param2] ...] ] + add_native_method("create", Method::CT_STATIC, _create, 1, MAX_CREATE_PARAMS + 2); // ^reflection:classes[] add_native_method("classes", Method::CT_STATIC, _classes, 0, 0);