|
|
| version 1.306, 2004/07/30 10:01:14 | version 1.313, 2005/08/09 08:14:51 |
|---|---|
| Line 1 | Line 1 |
| /** @file | /** @file |
| Parser: executor part of request class. | Parser: executor part of request class. |
| Copyright (c) 2001-2004 ArtLebedev Group (http://www.artlebedev.com) | Copyright (c) 2001-2005 ArtLebedev Group (http://www.artlebedev.com) |
| Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru) | Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru) |
| */ | */ |
| Line 186 void Request::execute(ArrayOperation& op | Line 186 void Request::execute(ArrayOperation& op |
| Value& value=stack.pop().value(); | Value& value=stack.pop().value(); |
| const String& name=stack.pop().string(); debug_name=&name; | const String& name=stack.pop().string(); debug_name=&name; |
| Value& ncontext=stack.pop().value(); | Value& ncontext=stack.pop().value(); |
| ncontext.put_element(name, &value, false); | put_element(ncontext, name, value); |
| break; | break; |
| } | } |
| case OP_CONSTRUCT_EXPR: | case OP_CONSTRUCT_EXPR: |
| Line 194 void Request::execute(ArrayOperation& op | Line 195 void Request::execute(ArrayOperation& op |
| // see OP_PREPARE_TO_EXPRESSION | // see OP_PREPARE_TO_EXPRESSION |
| wcontext->set_in_expression(false); | wcontext->set_in_expression(false); |
| Value& value=stack.pop().value(); | Value& expr=stack.pop().value(); |
| const String& name=stack.pop().string(); debug_name=&name; | const String& name=stack.pop().string(); debug_name=&name; |
| Value& ncontext=stack.pop().value(); | Value& ncontext=stack.pop().value(); |
| ncontext.put_element(name, &value.as_expr_result(), false); | Value& value=expr.as_expr_result(); |
| put_element(ncontext, name, value); | |
| break; | break; |
| } | } |
| case OP_CURLY_CODE__CONSTRUCT: | case OP_CURLY_CODE__CONSTRUCT: |
| Line 207 void Request::execute(ArrayOperation& op | Line 209 void Request::execute(ArrayOperation& op |
| debug_printf(sapi_info, " (%d)\n", local_ops.count()); | debug_printf(sapi_info, " (%d)\n", local_ops.count()); |
| debug_dump(sapi_info, 1, local_ops); | debug_dump(sapi_info, 1, local_ops); |
| #endif | #endif |
| Value& value=*new VJunction(new Junction( | Value& value=*new VJunction( |
| get_self(), 0, | get_self(), 0, |
| method_frame, | method_frame, |
| rcontext, | rcontext, |
| wcontext, | wcontext, |
| &local_ops)); | &local_ops); |
| const String& name=stack.pop().string(); debug_name=&name; | const String& name=stack.pop().string(); debug_name=&name; |
| Value& ncontext=stack.pop().value(); | Value& ncontext=stack.pop().value(); |
| ncontext.put_element(name, &value, false); | if(const VJunction* vjunction=ncontext.put_element(ncontext, name, &value, false)) |
| if(vjunction!=PUT_ELEMENT_REPLACED_ELEMENT) | |
| throw Exception("parser.runtime", | |
| 0, | |
| "property value can not be code, use [] or () brackets"); | |
| break; | break; |
| } | } |
| case OP_NESTED_CODE: | case OP_NESTED_CODE: |
| Line 350 void Request::execute(ArrayOperation& op | Line 357 void Request::execute(ArrayOperation& op |
| // hence, we zero junction.wcontext here, and later | // hence, we zero junction.wcontext here, and later |
| // in .process we would test that field | // in .process we would test that field |
| // in decision "which wwrapper to use" | // in decision "which wwrapper to use" |
| Value& value=*new VJunction(new Junction( | Value& value=*new VJunction( |
| get_self(), 0, | get_self(), 0, |
| method_frame, | method_frame, |
| rcontext, | rcontext, |
| opcode==OP_EXPR_CODE__STORE_PARAM?0:wcontext, | opcode==OP_EXPR_CODE__STORE_PARAM?0:wcontext, |
| &local_ops)); | &local_ops); |
| // store param | // store param |
| // this op is executed from CALL local_ops only, so can not check method_frame_to_fill==0 | // this op is executed from CALL local_ops only, so can not check method_frame_to_fill==0 |
| frame.store_param(value); | frame.store_param(value); |
| Line 425 void Request::execute(ArrayOperation& op | Line 432 void Request::execute(ArrayOperation& op |
| WContext *saved_wcontext=wcontext; | WContext *saved_wcontext=wcontext; |
| VStateless_class& called_class=*frame.junction.self.get_class(); | VStateless_class& called_class=*frame.junction.self.get_class(); |
| Value* new_self=&get_self(); | Value* new_self; |
| if(wcontext->get_constructing()) { | if(wcontext->get_constructing()) { |
| wcontext->set_constructing(false); | wcontext->set_constructing(false); |
| new_self=&get_self(); | |
| if(frame.junction.method->call_type!=Method::CT_STATIC) { | if(frame.junction.method->call_type!=Method::CT_STATIC) { |
| // this is a constructor call | // this is a constructor call |
| if(Value* value=called_class.create_new_value(fpool)) { | HashStringValue& new_object_fields=*new HashStringValue(); |
| if(Value* value=called_class.create_new_value(fpool, new_object_fields)) { | |
| // some stateless_class creatable derivates | // some stateless_class creatable derivates |
| new_self=value; | new_self=value; |
| } else | } else |
| Line 472 void Request::execute(ArrayOperation& op | Line 481 void Request::execute(ArrayOperation& op |
| *this, | *this, |
| *frame.numbered_params()); // execute it | *frame.numbered_params()); // execute it |
| } else // parser code, execute it | } else // parser code, execute it |
| recoursion_checked_execute(/*frame.name(), */*method.parser_code); | recoursion_checked_execute(*method.parser_code); |
| } else | } else |
| throw Exception("parser.runtime", | throw Exception("parser.runtime", |
| 0, //&frame.name(), | 0, //&frame.name(), |
| Line 828 Value& Request::get_element(Value& ncont | Line 837 Value& Request::get_element(Value& ncont |
| Value* value=0; | Value* value=0; |
| if(can_call_operator) { | if(can_call_operator) { |
| if(Method* method=main_class.get_method(name)) // looking operator of that name FIRST | if(Method* method=main_class.get_method(name)) // looking operator of that name FIRST |
| value=new VJunction(new Junction( | value=new VJunction(main_class, method); |
| main_class, method, 0,0,0, 0)); | |
| } | } |
| if(!value) { | if(!value) { |
| if(!wcontext->get_constructing() // not constructing | if(!wcontext->get_constructing() // not constructing |
| Line 864 value_ready: | Line 872 value_ready: |
| return *value; | return *value; |
| } | } |
| void Request::put_element(Value& ncontext, const String& name, Value& value) { | |
| // put_element can return property-setting-junction | |
| if(const VJunction* vjunction=ncontext.put_element(ncontext, name, &value, false)) | |
| if(vjunction!=PUT_ELEMENT_REPLACED_ELEMENT) { | |
| const Junction& junction=vjunction->junction(); | |
| // process it | |
| ArrayString* params_names=junction.method->params_names; | |
| int param_count=params_names? params_names->count(): 0; | |
| if(param_count!=1) | |
| throw Exception("parser.runtime", | |
| 0, | |
| "setter method must have ONE parameter (has %d parameters)", param_count); | |
| VMethodFrame frame(junction, method_frame/*caller*/); | |
| frame.store_param(value); | |
| frame.set_self(frame.junction.self); | |
| VMethodFrame *saved_method_frame=method_frame; | |
| Value* saved_rcontext=rcontext; | |
| WContext *saved_wcontext=wcontext; | |
| rcontext=wcontext=&frame; | |
| method_frame=&frame; | |
| // prevent non-string writes for better error reporting [setters are not expected to return anything] | |
| wcontext->write(*method_frame); | |
| recoursion_checked_execute(*frame.junction.method->parser_code); // parser code, execute it | |
| // we don't need it StringOrValue result=wcontext->result(); | |
| method_frame=saved_method_frame; | |
| wcontext=saved_wcontext; | |
| rcontext=saved_rcontext; | |
| } | |
| } | |
| /** @param intercept_string | /** @param intercept_string |
| - true: | - true: |
| they want result=string value, | they want result=string value, |
| Line 876 value_ready: | Line 921 value_ready: |
| using the fact it's either string_ or value_ result requested to speed up checkes | using the fact it's either string_ or value_ result requested to speed up checkes |
| */ | */ |
| StringOrValue Request::process(Value& input_value, bool intercept_string) { | StringOrValue Request::process(Value& input_value, bool intercept_string) { |
| StringOrValue result; | |
| Junction* junction=input_value.get_junction(); | Junction* junction=input_value.get_junction(); |
| if(junction && junction->code) { // is it a code-junction? | if(junction) { |
| // process it | if(junction->is_getter) { // is it a getter-junction? |
| // process it | |
| VMethodFrame frame(*junction, method_frame/*caller*/); | |
| if(junction->method->params_names) | |
| throw Exception("parser.runtime", | |
| 0, | |
| "getter method must have no parameters"); | |
| frame.set_self(frame.junction.self); | |
| VMethodFrame *saved_method_frame=method_frame; | |
| Value* saved_rcontext=rcontext; | |
| WContext *saved_wcontext=wcontext; | |
| rcontext=wcontext=&frame; | |
| method_frame=&frame; | |
| recoursion_checked_execute(*frame.junction.method->parser_code); // parser code, execute it | |
| StringOrValue result=wcontext->result(); | |
| method_frame=saved_method_frame; | |
| wcontext=saved_wcontext; | |
| rcontext=saved_rcontext; | |
| return result; | |
| } | |
| if(junction->code) { // is it a code-junction? | |
| // process it | |
| StringOrValue result; | |
| #ifdef DEBUG_EXECUTE | #ifdef DEBUG_EXECUTE |
| debug_printf(sapi_info, "ja->\n"); | debug_printf(sapi_info, "ja->\n"); |
| #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"); |
| 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; |
| method_frame=junction->method_frame; | method_frame=junction->method_frame; |
| rcontext=junction->rcontext; | rcontext=junction->rcontext; |
| // for expression method params | // for expression method params |
| // wcontext is set 0 | // wcontext is set 0 |
| // 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 | // BUT intercepts string writes |
| VCodeFrame local(*junction->wcontext, junction->wcontext); | VCodeFrame local(*junction->wcontext, junction->wcontext); |
| wcontext=&local; | wcontext=&local; |
| // execute it | |
| recoursion_checked_execute(*junction->code); | |
| // CodeFrame soul: | |
| // string writes were intercepted | |
| // returning them as the result of getting code-junction | |
| result.set_string(*wcontext->get_string()); | |
| } else { | |
| // plain wwrapper | |
| WWrapper local(0/*empty*/, wcontext); | |
| wcontext=&local; | |
| // execute it | |
| recoursion_checked_execute(*junction->code); | |
| result=wcontext->result(); | |
| } | |
| wcontext=saved_wcontext; | |
| rcontext=saved_rcontext; | |
| method_frame=saved_method_frame; | |
| // execute it | |
| recoursion_checked_execute(*junction->code); | |
| // CodeFrame soul: | |
| // string writes were intercepted | |
| // returning them as the result of getting code-junction | |
| result.set_string(*wcontext->get_string()); | |
| } else { | |
| // plain wwrapper | |
| WWrapper local(0/*empty*/, wcontext); | |
| wcontext=&local; | |
| // execute it | |
| recoursion_checked_execute(*junction->code); | |
| result=wcontext->result(); | |
| } | |
| wcontext=saved_wcontext; | |
| rcontext=saved_rcontext; | |
| method_frame=saved_method_frame; | |
| #ifdef DEBUG_EXECUTE | #ifdef DEBUG_EXECUTE |
| debug_printf(sapi_info, "<-ja returned"); | debug_printf(sapi_info, "<-ja returned"); |
| #endif | #endif |
| } else { | return result; |
| result.set_value(input_value); | } |
| } | |
| return result; | // it is then method-junction, do not explode it |
| // just return it as we do for usual objects | |
| } | |
| return input_value; | |
| } | } |
| StringOrValue Request::execute_method(VMethodFrame& amethod_frame, const Method& method) { | StringOrValue Request::execute_method(VMethodFrame& amethod_frame, const Method& method) { |
| Line 966 const String* Request::execute_method(Va | Line 1044 const String* Request::execute_method(Va |
| Value* saved_rcontext=rcontext; | Value* saved_rcontext=rcontext; |
| WContext *saved_wcontext=wcontext; | WContext *saved_wcontext=wcontext; |
| Junction local_junction(aself, &method, 0,0,0, 0); | Junction local_junction(aself, &method); |
| VMethodFrame local_frame(local_junction, method_frame/*caller*/); | VMethodFrame 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); |