--- parser3/src/main/execute.C 2003/04/02 11:35:20 1.295.2.27.2.13 +++ parser3/src/main/execute.C 2005/07/26 12:43:05 1.308 @@ -1,11 +1,11 @@ /** @file Parser: executor part of request class. - Copyright (c) 2001-2003 ArtLebedev Group (http://www.artlebedev.com) + Copyright (c) 2001-2004 ArtLebedev Group (http://www.artlebedev.com) Author: Alexandr Petrosian (http://paf.design.ru) */ -static const char* IDENT_EXECUTE_C="$Date: 2003/04/02 11:35:20 $"; +static const char * const IDENT_EXECUTE_C="$Date: 2005/07/26 12:43:05 $"; #include "pa_opcode.h" #include "pa_array.h" @@ -24,7 +24,6 @@ static const char* IDENT_EXECUTE_C="$Dat #include "pa_wwrapper.h" //#define DEBUG_EXECUTE -#define LATER_STACK_TRACE #ifdef DEBUG_EXECUTE char *opcode_name[]={ @@ -71,20 +70,21 @@ void debug_printf(SAPI_Info& sapi_info, void debug_dump(SAPI_Info& sapi_info, int level, ArrayOperation& ops) { Array_iterator i(ops); while(i.has_next()) { - Operation op=i.next(); + OPCODE opcode=i.next().code; - if(op.code==OP_VALUE || op.code==OP_STRING__WRITE) { + if(opcode==OP_VALUE || opcode==OP_STRING__WRITE) { + Operation::Origin origin=i.next().origin; Value& value=*i.next().value; debug_printf(sapi_info, "%*s%s" " \"%s\" %s", - level*4, "", opcode_name[op.code], + level*4, "", opcode_name[opcode], value.get_string()->cstr(), value.type()); continue; } - debug_printf(sapi_info, "%*s%s", level*4, "", opcode_name[op.code]); + debug_printf(sapi_info, "%*s%s", level*4, "", opcode_name[opcode]); - switch(op.code) { + switch(opcode) { case OP_CURLY_CODE__STORE_PARAM: case OP_EXPR_CODE__STORE_PARAM: case OP_CURLY_CODE__CONSTRUCT: @@ -105,6 +105,8 @@ void debug_dump(SAPI_Info& sapi_info, in void Request::execute(ArrayOperation& ops) { register Stack& stack=this->stack; // helps a lot on MSVC: 'esi' + const String* debug_name=0; Operation::Origin debug_origin={0, 0, 0}; + try{ #ifdef DEBUG_EXECUTE debug_printf(sapi_info, "source----------------------------\n"); debug_dump(sapi_info, 0, ops); @@ -118,6 +120,7 @@ void Request::execute(ArrayOperation& op "execution stopped"); } OPCODE opcode=i.next().code; + #ifdef DEBUG_EXECUTE debug_printf(sapi_info, "%d:%s", stack.top_index()+1, opcode_name[opcode]); #endif @@ -126,6 +129,7 @@ void Request::execute(ArrayOperation& op // param in next instruction case OP_VALUE: { + debug_origin=i.next().origin; Value& value=*i.next().value; #ifdef DEBUG_EXECUTE debug_printf(sapi_info, " \"%s\" %s", value.get_string()->cstr(), value.type()); @@ -180,9 +184,44 @@ void Request::execute(ArrayOperation& op case OP_CONSTRUCT_VALUE: { Value& value=stack.pop().value(); - const String& name=stack.pop().string(); + const String& name=stack.pop().string(); debug_name=&name; Value& ncontext=stack.pop().value(); - ncontext.put_element(name, &value, false); + + // put_element can return property-setting-junction + if(const Junction* junction=ncontext.put_element(name, &value, false)) + if(junction!=PUT_ELEMENT_REPLACED_ELEMENT) { + // 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); + + // TODO: move that to this::execute_method [fix it's param types] + 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 + 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; + } + break; } case OP_CONSTRUCT_EXPR: @@ -190,10 +229,16 @@ void Request::execute(ArrayOperation& op // see OP_PREPARE_TO_EXPRESSION wcontext->set_in_expression(false); - Value& value=stack.pop().value(); - const String& name=stack.pop().string(); + Value& expr=stack.pop().value(); + const String& name=stack.pop().string(); debug_name=&name; Value& ncontext=stack.pop().value(); - ncontext.put_element(name, &value.as_expr_result(), false); + Value& value=expr.as_expr_result(); + if(const Junction* junction=ncontext.put_element(name, &value, false)) + if(junction!=PUT_ELEMENT_REPLACED_ELEMENT) { + throw Exception("parser.runtime", + 0, + "TODO:paf -- $property(value)"); + } break; } case OP_CURLY_CODE__CONSTRUCT: @@ -210,9 +255,14 @@ void Request::execute(ArrayOperation& op wcontext, &local_ops)); - const String& name=stack.pop().string(); + const String& name=stack.pop().string(); debug_name=&name; Value& ncontext=stack.pop().value(); - ncontext.put_element(name, &value, false); + if(const Junction* junction=ncontext.put_element(name, &value, false)) + if(junction!=PUT_ELEMENT_REPLACED_ELEMENT) + throw Exception("parser.runtime", + 0, + "property value can not be code, use [] or () brackets"); + break; } case OP_NESTED_CODE: @@ -243,6 +293,7 @@ void Request::execute(ArrayOperation& op } case OP_STRING__WRITE: { + i.next(); // ignore origin Value* value=i.next().value; #ifdef DEBUG_EXECUTE debug_printf(sapi_info, " \"%s\"", value->get_string()->cstr()); @@ -253,20 +304,26 @@ void Request::execute(ArrayOperation& op case OP_GET_ELEMENT_OR_OPERATOR: { - Value& value=get_element(true); + const String& name=stack.pop().string(); debug_name=&name; + Value& ncontext=stack.pop().value(); + Value& value=get_element(ncontext, name, true); stack.push(value); break; } case OP_GET_ELEMENT: { - Value& value=get_element(false); + const String& name=stack.pop().string(); debug_name=&name; + Value& ncontext=stack.pop().value(); + Value& value=get_element(ncontext, name, false); stack.push(value); break; } case OP_GET_ELEMENT__WRITE: { - Value& value=get_element(false); + const String& name=stack.pop().string(); debug_name=&name; + Value& ncontext=stack.pop().value(); + Value& value=get_element(ncontext, name, false); write_assign_lang(value); break; } @@ -366,6 +423,7 @@ void Request::execute(ArrayOperation& op case OP_CALL: case OP_CALL__WRITE: { + //is_debug_junction=true; ArrayOperation* local_ops=i.next().ops; #ifdef DEBUG_EXECUTE debug_printf(sapi_info, " (%d)\n", local_ops?local_ops->count():0); @@ -377,11 +435,17 @@ void Request::execute(ArrayOperation& op Value& value=stack.pop().value(); Junction* junction=value.get_junction(); - if(!junction) - throw Exception("parser.runtime", - 0, - "(%s) not a method or junction, can not call it", - value.type()); + if(!junction) { + if(value.is("void")) + throw Exception("parser.runtime", + 0, + "undefined method"); + else + throw Exception("parser.runtime", + 0, + "is '%s', not a method or junction, can not call it", + value.type()); + } /* no check needed, code compiled the way that that's impossible // check: // that this is method-junction, not a code-junction @@ -391,7 +455,7 @@ void Request::execute(ArrayOperation& op if(!junction->method) throw Exception("parser.runtime", - "(%s) is code junction, can not call it", + "is '%s', it is code junction, can not call it", value.type()); */ @@ -407,13 +471,14 @@ void Request::execute(ArrayOperation& op WContext *saved_wcontext=wcontext; VStateless_class& called_class=*frame.junction.self.get_class(); - Value* new_self=&get_self(); + 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 - if(Value* value=called_class.create_new_value()) { + if(Value* value=called_class.create_new_value(fpool)) { // some stateless_class creatable derivates new_self=value; } else @@ -445,26 +510,16 @@ void Request::execute(ArrayOperation& op if( method.call_type==Method::CT_ANY || method.call_type==call_type) { // allowed call type? -#ifndef LATER_STACK_TRACE - try { -#endif - 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.name(), */frame.numbered_params()); // execute it - } else // parser code, execute it - recoursion_checked_execute(/*frame.name(), */*method.parser_code); -#ifndef LATER_STACK_TRACE - } catch(...) { - // record it to stack trace - exception_trace.push(frame.name()); - rethrow; - } -#endif + 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(), @@ -487,6 +542,7 @@ void Request::execute(ArrayOperation& op #ifdef DEBUG_EXECUTE debug_printf(sapi_info, "<-returned"); #endif + //is_debug_junction=false; break; } @@ -701,49 +757,49 @@ void Request::execute(ArrayOperation& op } case OP_NUM_LT: { - Value& b=stack.pop().value(); Value& a=stack.pop().value(); - double result=a.as_double() - b.as_double(); - Value& value=*new VBool(result < 0.0); + volatile double b_double=stack.pop().value().as_double(); + volatile double a_double=stack.pop().value().as_double(); + Value& value=*new VBool(a_double 0.0); + volatile double b_double=stack.pop().value().as_double(); + volatile double a_double=stack.pop().value().as_double(); + Value& value=*new VBool(a_double>b_double); stack.push(value); break; } case OP_NUM_LE: { - Value& b=stack.pop().value(); Value& a=stack.pop().value(); - double result=a.as_double() - b.as_double(); - Value& value=*new VBool(result <= 0.0); + volatile double b_double=stack.pop().value().as_double(); + volatile double a_double=stack.pop().value().as_double(); + Value& value=*new VBool(a_double<=b_double); stack.push(value); break; } case OP_NUM_GE: { - Value& b=stack.pop().value(); Value& a=stack.pop().value(); - double result=a.as_double() - b.as_double(); - Value& value=*new VBool(result >= 0.0); + volatile double b_double=stack.pop().value().as_double(); + volatile double a_double=stack.pop().value().as_double(); + Value& value=*new VBool(a_double>=b_double); stack.push(value); break; } case OP_NUM_EQ: { - Value& b=stack.pop().value(); Value& a=stack.pop().value(); - double result=a.as_double() - b.as_double(); - Value& value=*new VBool(result == 0.0); + volatile double b_double=stack.pop().value().as_double(); + volatile double a_double=stack.pop().value().as_double(); + Value& value=*new VBool(a_double==b_double); stack.push(value); break; } case OP_NUM_NE: { - Value& b=stack.pop().value(); Value& a=stack.pop().value(); - double result=a.as_double() - b.as_double(); - Value& value=*new VBool(result != 0.0); + volatile double b_double=stack.pop().value().as_double(); + volatile double a_double=stack.pop().value().as_double(); + Value& value=*new VBool(a_double!=b_double); stack.push(value); break; } @@ -803,20 +859,23 @@ void Request::execute(ArrayOperation& op "invalid opcode %d", opcode); } } + } catch(const Exception&) { + // record it to stack trace + if(debug_name) + exception_trace.push(Trace(debug_name, debug_origin)); + rethrow; + } } /** @todo cache|prepare junctions @bug ^superbase:method would dynamically call ^base:method if there is any */ -Value& Request::get_element(bool can_call_operator) { - const String& name=stack.pop().string(); //remember_name=name; - Value& ncontext=stack.pop().value(); +Value& Request::get_element(Value& ncontext, const String& name, bool can_call_operator) { Value* value=0; if(can_call_operator) { if(Method* method=main_class.get_method(name)) // looking operator of that name FIRST - value=new VJunction(new Junction( - main_class, method, 0,0,0, 0)); + value=new VJunction(new Junction(main_class, method)); } if(!value) { if(!wcontext->get_constructing() // not constructing @@ -863,68 +922,101 @@ value_ready: 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 result; Junction* junction=input_value.get_junction(); - if(junction && junction->code) { // is it a code-junction? - // process it + if(junction) { + 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 - debug_printf(sapi_info, "ja->\n"); + debug_printf(sapi_info, "ja->\n"); #endif - if(!junction->method_frame) - throw Exception("parser.runtime", + if(!junction->method_frame) + throw Exception("parser.runtime", 0, "junction used outside of context"); - VMethodFrame *saved_method_frame=method_frame; - Value* saved_rcontext=rcontext; - WContext *saved_wcontext=wcontext; - - method_frame=junction->method_frame; - rcontext=junction->rcontext; - - // for expression method params - // wcontext is set 0 - // using the fact in decision "which wwrapper to use" - bool using_code_frame=intercept_string && junction->wcontext; - if(using_code_frame) { - // almost plain wwrapper about junction wcontext, - // BUT intercepts string writes - VCodeFrame local(*junction->wcontext, junction->wcontext); - wcontext=&local; + VMethodFrame *saved_method_frame=method_frame; + Value* saved_rcontext=rcontext; + WContext *saved_wcontext=wcontext; + + method_frame=junction->method_frame; + rcontext=junction->rcontext; + + // for expression method params + // wcontext is set 0 + // using the fact in decision "which wwrapper to use" + bool using_code_frame=intercept_string && junction->wcontext; + if(using_code_frame) { + // almost plain wwrapper about junction wcontext, + // BUT intercepts string writes + VCodeFrame local(*junction->wcontext, junction->wcontext); + 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(/*0/*result_name* /, */ *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(/*0/*result_name* /, */ *junction->code); - - result=wcontext->result(); - } - - wcontext=saved_wcontext; - rcontext=saved_rcontext; - method_frame=saved_method_frame; - #ifdef DEBUG_EXECUTE - debug_printf(sapi_info, "<-ja returned"); + debug_printf(sapi_info, "<-ja returned"); #endif - } else { - result.set_value(input_value); - } - return result; + return result; + } + + // it is then method-junction, do not explode it + // just return it as we do for usual objects + } + + return input_value; } -const String& Request::execute_method(VMethodFrame& amethod_frame, const Method& method) { +StringOrValue Request::execute_method(VMethodFrame& amethod_frame, const Method& method) { VMethodFrame *saved_method_frame=method_frame; Value* saved_rcontext=rcontext; WContext *saved_wcontext=wcontext; @@ -936,7 +1028,7 @@ const String& Request::execute_method(VM execute(*method.parser_code); // result - const String& result=wcontext->result().as_string(); + StringOrValue result=wcontext->result(); wcontext=saved_wcontext; rcontext=saved_rcontext; @@ -947,14 +1039,14 @@ const String& Request::execute_method(VM } const String* Request::execute_method(Value& aself, - const Method& method, VString* optional_param, - bool do_return_string) { + const Method& method, VString* optional_param, + bool do_return_string) { VMethodFrame *saved_method_frame=method_frame; Value* saved_rcontext=rcontext; WContext *saved_wcontext=wcontext; - Junction local_junction(aself, &method, 0,0,0, 0); - VMethodFrame local_frame(/*method.name, */local_junction, method_frame/*caller*/); + Junction local_junction(aself, &method); + VMethodFrame local_frame(local_junction, method_frame/*caller*/); if(optional_param && local_frame.can_store_param()) { local_frame.store_param(*optional_param); local_frame.fill_unspecified_params();