|
|
| version 1.315, 2006/04/09 13:38:47 | version 1.320, 2008/06/05 13:32:43 |
|---|---|
| Line 14 static const char * const IDENT_EXECUTE_ | Line 14 static const char * const IDENT_EXECUTE_ |
| #include "pa_vhash.h" | #include "pa_vhash.h" |
| #include "pa_vvoid.h" | #include "pa_vvoid.h" |
| #include "pa_vcode_frame.h" | #include "pa_vcode_frame.h" |
| #include "pa_vmethod_frame.h" | #include "pa_vmethod_frame_local.h" |
| #include "pa_vmethod_frame_global.h" | |
| #include "pa_vobject.h" | #include "pa_vobject.h" |
| #include "pa_vdouble.h" | #include "pa_vdouble.h" |
| #include "pa_vbool.h" | #include "pa_vbool.h" |
| Line 147 void Request::execute(ArrayOperation& op | Line 148 void Request::execute(ArrayOperation& op |
| const String& name=stack.pop().string(); | const String& name=stack.pop().string(); |
| Value* value=classes().get(name); | Value* value=classes().get(name); |
| if(!value) | if(!value) |
| throw Exception("parser.runtime", | throw Exception(PARSER_RUNTIME, |
| &name, | &name, |
| "class is undefined"); | "class is undefined"); |
| Line 174 void Request::execute(ArrayOperation& op | Line 175 void Request::execute(ArrayOperation& op |
| case OP_WITH_WRITE: | case OP_WITH_WRITE: |
| { | { |
| if(wcontext==method_frame) | if(wcontext==method_frame) |
| throw Exception("parser.runtime", | throw Exception(PARSER_RUNTIME, |
| 0, | 0, |
| "$.name outside of $name[...]"); | "$.name outside of $name[...]"); |
| Line 222 void Request::execute(ArrayOperation& op | Line 223 void Request::execute(ArrayOperation& op |
| Value& ncontext=stack.pop().value(); | Value& ncontext=stack.pop().value(); |
| if(const VJunction* vjunction=ncontext.put_element(ncontext, name, &value, false)) | if(const VJunction* vjunction=ncontext.put_element(ncontext, name, &value, false)) |
| if(vjunction!=PUT_ELEMENT_REPLACED_ELEMENT) | if(vjunction!=PUT_ELEMENT_REPLACED_ELEMENT) |
| throw Exception("parser.runtime", | throw Exception(PARSER_RUNTIME, |
| 0, | 0, |
| "property value can not be code, use [] or () brackets"); | "property value can not be code, use [] or () brackets"); |
| Line 400 void Request::execute(ArrayOperation& op | Line 401 void Request::execute(ArrayOperation& op |
| Junction* junction=value.get_junction(); | Junction* junction=value.get_junction(); |
| if(!junction) { | if(!junction) { |
| if(value.is("void")) | if(value.is("void")) |
| throw Exception("parser.runtime", | throw Exception(PARSER_RUNTIME, |
| 0, | 0, |
| "undefined method"); | "undefined method"); |
| else | else |
| throw Exception("parser.runtime", | throw Exception(PARSER_RUNTIME, |
| 0, | 0, |
| "is '%s', not a method or junction, can not call it", | "is '%s', not a method or junction, can not call it", |
| value.type()); | value.type()); |
| Line 416 void Request::execute(ArrayOperation& op | Line 417 void Request::execute(ArrayOperation& op |
| // $junction{code} | // $junction{code} |
| // ^junction[] | // ^junction[] |
| if(!junction->method) | if(!junction->method) |
| throw Exception("parser.runtime", | throw Exception(PARSER_RUNTIME, |
| "is '%s', it is code junction, can not call it", | "is '%s', it is code junction, can not call it", |
| value.type()); | value.type()); |
| */ | */ |
| VMethodFrame frame(*junction, method_frame/*caller*/); | if(junction->method->all_vars_local){ |
| if(local_ops){ // store param code goes here | VMethodFrameLocal frame(*junction, method_frame); |
| stack.push(frame); // argument for *STORE_PARAM ops | if(local_ops){ // store param code goes here |
| execute(*local_ops); | stack.push(frame); // argument for *STORE_PARAM ops |
| stack.pop().value(); | execute(*local_ops); |
| stack.pop().value(); | |
| } | |
| WContext* result_wcontext=op_call(frame); | |
| if(opcode==OP_CALL__WRITE) { | |
| write_assign_lang(result_wcontext->result()); | |
| } else { // OP_CALL | |
| stack.push(result_wcontext->result().as_value()); | |
| } | |
| } else { | |
| VMethodFrameGlobal frame(*junction, method_frame); | |
| if(local_ops){ // store param code goes here | |
| stack.push(frame); // argument for *STORE_PARAM ops | |
| execute(*local_ops); | |
| stack.pop().value(); | |
| } | |
| WContext* result_wcontext=op_call(frame); | |
| if(opcode==OP_CALL__WRITE) { | |
| write_assign_lang(result_wcontext->result()); | |
| } else { // OP_CALL | |
| stack.push(result_wcontext->result().as_value()); | |
| } | |
| } | } |
| frame.fill_unspecified_params(); | |
| VMethodFrame *saved_method_frame=method_frame; | |
| Value* saved_rcontext=rcontext; | |
| WContext *saved_wcontext=wcontext; | |
| VStateless_class& called_class=*frame.junction.self.get_class(); | |
| Value* new_self; | |
| if(wcontext->get_constructing()) { | |
| wcontext->set_constructing(false); | |
| new_self=&get_self(); | |
| if(frame.junction.method->call_type!=Method::CT_STATIC) { | |
| // this is a constructor call | |
| HashStringValue& new_object_fields=*new HashStringValue(); | |
| if(Value* value=called_class.create_new_value(fpool, new_object_fields)) { | |
| // some stateless_class creatable derivates | |
| new_self=value; | |
| } else | |
| throw Exception("parser.runtime", | |
| 0, //&frame.name(), | |
| "is not a constructor, system class '%s' can be constructed only implicitly", | |
| called_class.name().cstr()); | |
| frame.write(*new_self, | |
| String::L_CLEAN // not used, always an object, not string | |
| ); | |
| } else | |
| throw Exception("parser.runtime", | |
| 0, //&frame.name(), | |
| "method is static and can not be used as constructor"); | |
| } else | |
| new_self=&frame.junction.self; | |
| frame.set_self(*new_self); | |
| // see OP_PREPARE_TO_EXPRESSION | |
| frame.set_in_expression(wcontext->get_in_expression()); | |
| rcontext=wcontext=&frame; | |
| { | |
| const Method& method=*frame.junction.method; | |
| Method::Call_type call_type= | |
| &called_class==new_self ? Method::CT_STATIC : Method::CT_DYNAMIC; | |
| if( | |
| method.call_type==Method::CT_ANY || | |
| method.call_type==call_type) { // allowed call type? | |
| method_frame=&frame; | |
| if(method.native_code) { // native code? | |
| method.check_actual_numbered_params( | |
| frame.junction.self, | |
| /*frame.name(), */frame.numbered_params()); | |
| method.native_code( | |
| *this, | |
| *frame.numbered_params()); // execute it | |
| } else // parser code, execute it | |
| recoursion_checked_execute(*method.parser_code); | |
| } else | |
| throw Exception("parser.runtime", | |
| 0, //&frame.name(), | |
| "is not allowed to be called %s", | |
| call_type==Method::CT_STATIC?"statically":"dynamically"); | |
| } | |
| StringOrValue result=wcontext->result(); | |
| wcontext=saved_wcontext; | |
| rcontext=saved_rcontext; | |
| method_frame=saved_method_frame; | |
| if(opcode==OP_CALL__WRITE) { | |
| write_assign_lang(result); | |
| } else { // OP_CALL | |
| stack.push(result.as_value()); | |
| } | |
| #ifdef DEBUG_EXECUTE | #ifdef DEBUG_EXECUTE |
| debug_printf(sapi_info, "<-returned"); | debug_printf(sapi_info, "<-returned"); |
| #endif | #endif |
| Line 831 void Request::execute(ArrayOperation& op | Line 778 void Request::execute(ArrayOperation& op |
| } | } |
| } | } |
| WContext* Request::op_call(VMethodFrame& frame){ | |
| frame.fill_unspecified_params(); | |
| VMethodFrame *saved_method_frame=method_frame; | |
| Value* saved_rcontext=rcontext; | |
| WContext *saved_wcontext=wcontext; | |
| VStateless_class& called_class=*frame.junction.self.get_class(); | |
| Value* new_self; | |
| if(wcontext->get_constructing()) { | |
| wcontext->set_constructing(false); | |
| new_self=&get_self(); | |
| if(frame.junction.method->call_type!=Method::CT_STATIC) { | |
| // this is a constructor call | |
| HashStringValue& new_object_fields=*new HashStringValue(); | |
| if(Value* value=called_class.create_new_value(fpool, new_object_fields)) { | |
| // some stateless_class creatable derivates | |
| new_self=value; | |
| } else | |
| throw Exception(PARSER_RUNTIME, | |
| 0, //&frame.name(), | |
| "is not a constructor, system class '%s' can be constructed only implicitly", | |
| called_class.name().cstr()); | |
| frame.write(*new_self, | |
| String::L_CLEAN // not used, always an object, not string | |
| ); | |
| } else | |
| throw Exception(PARSER_RUNTIME, | |
| 0, //&frame.name(), | |
| "method is static and can not be used as constructor"); | |
| } else | |
| new_self=&frame.junction.self; | |
| frame.set_self(*new_self); | |
| // see OP_PREPARE_TO_EXPRESSION | |
| frame.set_in_expression(wcontext->get_in_expression()); | |
| rcontext=wcontext=&frame; | |
| { | |
| const Method& method=*frame.junction.method; | |
| Method::Call_type call_type=&called_class==new_self ? Method::CT_STATIC : Method::CT_DYNAMIC; | |
| if( | |
| method.call_type==Method::CT_ANY || | |
| method.call_type==call_type) { // allowed call type? | |
| method_frame=&frame; | |
| if(method.native_code) { // native code? | |
| method.check_actual_numbered_params( | |
| frame.junction.self, | |
| /*frame.name(), */frame.numbered_params()); | |
| method.native_code( | |
| *this, | |
| *frame.numbered_params()); // execute it | |
| } else // parser code, execute it | |
| recoursion_checked_execute(*method.parser_code); | |
| } else | |
| throw Exception(PARSER_RUNTIME, | |
| 0, //&frame.name(), | |
| "is not allowed to be called %s", | |
| call_type==Method::CT_STATIC?"statically":"dynamically"); | |
| } | |
| WContext *result_wcontext=wcontext; | |
| // StringOrValue result=wcontext->result(); | |
| wcontext=saved_wcontext; | |
| rcontext=saved_rcontext; | |
| method_frame=saved_method_frame; | |
| return result_wcontext; | |
| } | |
| /** | /** |
| @todo cache|prepare junctions | @todo cache|prepare junctions |
| @bug ^superbase:method would dynamically call ^base:method if there is any | @bug ^superbase:method would dynamically call ^base:method if there is any |
| Line 849 Value& Request::get_element(Value& ncont | Line 869 Value& Request::get_element(Value& ncont |
| if(read_class->derived_from(*called_class)) // current derived from called | if(read_class->derived_from(*called_class)) // current derived from called |
| if(Value* base=get_self().base()) { // doing DYNAMIC call | if(Value* base=get_self().base()) { // doing DYNAMIC call |
| Temp_derived temp_derived(*base, 0); // temporarily prevent go-back-down virtual calls | Temp_derived temp_derived(*base, 0); // temporarily prevent go-back-down virtual calls |
| value=base->get_element(name, *base, false); // virtual-up lookup starting from parent | value=base->get_element(name, *base, true); // virtual-up lookup starting from parent |
| goto value_ready; | goto value_ready; |
| } | } |
| } | } |
| if(!value) | if(!value) |
| value=ncontext.get_element(name, ncontext, false); | value=ncontext.get_element(name, ncontext, true); |
| if(value && wcontext->get_constructing()) | if(value && wcontext->get_constructing()) |
| if(Junction* junction=value->get_junction()) { | if(Junction* junction=value->get_junction()) { |
| if(junction->self.get_class()!=&ncontext) | if(junction->self.get_class()!=&ncontext) |
| throw Exception("parser.runtime", | throw Exception(PARSER_RUNTIME, |
| &name, | &name, |
| "constructor must be declared in class '%s'", | "constructor must be declared in class '%s'", |
| ncontext.get_class()->name_cstr()); | ncontext.get_class()->name_cstr()); |
| Line 883 void Request::put_element(Value& ncontex | Line 903 void Request::put_element(Value& ncontex |
| ArrayString* params_names=junction.method->params_names; | ArrayString* params_names=junction.method->params_names; |
| int param_count=params_names? params_names->count(): 0; | int param_count=params_names? params_names->count(): 0; |
| if(param_count!=1) | if(param_count!=1) |
| throw Exception("parser.runtime", | throw Exception(PARSER_RUNTIME, |
| 0, | 0, |
| "setter method must have ONE parameter (has %d parameters)", param_count); | "setter method must have ONE parameter (has %d parameters)", param_count); |
| VMethodFrame frame(junction, method_frame/*caller*/); | VMethodFrameGlobal frame(junction, method_frame/*caller*/); |
| frame.store_param(value); | frame.store_param(value); |
| frame.set_self(frame.junction.self); | frame.set_self(frame.junction.self); |
| Line 926 StringOrValue Request::process(Value& in | Line 946 StringOrValue Request::process(Value& in |
| Junction* junction=input_value.get_junction(); | Junction* junction=input_value.get_junction(); |
| if(junction) { | if(junction) { |
| if(junction->is_getter) { // is it a getter-junction? | if(junction->is_getter) { // is it a getter-junction? |
| // process it | int param_count=junction->method->params_names?junction->method->params_names->count():0; |
| if(junction->auto_name){ // default getter | |
| VMethodFrame frame(*junction, method_frame/*caller*/); | if(param_count>1) |
| if(junction->method->params_names) | throw Exception(PARSER_RUNTIME, |
| throw Exception("parser.runtime", | 0, |
| "default getter method can't have more then 1 parameter (has %d parameters)", param_count); | |
| } else if(param_count) | |
| throw Exception(PARSER_RUNTIME, | |
| 0, | 0, |
| "getter method must have no parameters"); | "getter method must have no parameters (has %d parameters)", param_count); |
| VMethodFrameGlobal frame(*junction, method_frame/*caller*/); | |
| if(junction->auto_name && param_count) | |
| frame.store_param(*new VString(*junction->auto_name)); | |
| frame.set_self(frame.junction.self); | frame.set_self(frame.junction.self); |
| Line 961 StringOrValue Request::process(Value& in | Line 989 StringOrValue Request::process(Value& in |
| #endif | #endif |
| if(!junction->method_frame) | if(!junction->method_frame) |
| throw Exception("parser.runtime", | throw Exception(PARSER_RUNTIME, |
| 0, | 0, |
| "junction used outside of context"); | "junction used outside of context"); |
| Line 977 StringOrValue Request::process(Value& in | Line 1005 StringOrValue Request::process(Value& in |
| // using the fact in decision "which wwrapper to use" | // using the fact in decision "which wwrapper to use" |
| bool using_code_frame=intercept_string && junction->wcontext; | bool using_code_frame=intercept_string && junction->wcontext; |
| if(using_code_frame) { | if(using_code_frame) { |
| // almost plain wwrapper about junction wcontext, | // almost plain wwrapper about junction wcontext |
| // BUT intercepts string writes | |
| VCodeFrame local(*junction->wcontext, junction->wcontext); | VCodeFrame local(*junction->wcontext); |
| wcontext=&local; | wcontext=&local; |
| // execute it | // execute it |
| recoursion_checked_execute(*junction->code); | recoursion_checked_execute(*junction->code); |
| // CodeFrame soul: | // CodeFrame soul: |
| // string writes were intercepted | result=wcontext->result(); |
| // returning them as the result of getting code-junction | |
| result.set_string(*wcontext->get_string()); | |
| } else { | } else { |
| // plain wwrapper | // plain wwrapper |
| WWrapper local(0/*empty*/, wcontext); | WWrapper local(0/*empty*/, wcontext); |
| Line 1042 StringOrValue Request::execute_method(VM | Line 1068 StringOrValue Request::execute_method(VM |
| const String* Request::execute_method(Value& aself, | const String* Request::execute_method(Value& aself, |
| const Method& method, VString* optional_param, | const Method& method, VString* optional_param, |
| bool do_return_string) { | bool do_return_string) { |
| VMethodFrame *saved_method_frame=method_frame; | VMethodFrame *saved_method_frame=method_frame; |
| Value* saved_rcontext=rcontext; | Value* saved_rcontext=rcontext; |
| WContext *saved_wcontext=wcontext; | WContext *saved_wcontext=wcontext; |
| Junction local_junction(aself, &method); | Junction local_junction(aself, &method); |
| VMethodFrame local_frame(local_junction, method_frame/*caller*/); | VMethodFrameGlobal local_frame(local_junction, method_frame/*caller*/); |
| if(optional_param && local_frame.can_store_param()) { | if(optional_param && local_frame.can_store_param()) { |
| local_frame.store_param(*optional_param); | local_frame.store_param(*optional_param); |
| local_frame.fill_unspecified_params(); | local_frame.fill_unspecified_params(); |
| Line 1076 const String* Request::execute_method(Va | Line 1103 const String* Request::execute_method(Va |
| Request::Execute_nonvirtual_method_result | Request::Execute_nonvirtual_method_result |
| Request::execute_nonvirtual_method(VStateless_class& aclass, | Request::execute_nonvirtual_method(VStateless_class& aclass, |
| const String& method_name, VString* optional_param, | const String& method_name, |
| VString* optional_param, | |
| bool do_return_string) { | bool do_return_string) { |
| Execute_nonvirtual_method_result result; | Execute_nonvirtual_method_result result; |
| result.method=aclass.get_method(method_name); | result.method=aclass.get_method(method_name); |
| if(result.method) | if(result.method) |
| result.string=execute_method(aclass, *result.method, optional_param, | result.string=execute_method(aclass, *result.method, optional_param, do_return_string); |
| do_return_string); | |
| return result; | return result; |
| } | } |