--- parser3/src/main/execute.C 2002/04/18 11:41:29 1.237 +++ parser3/src/main/execute.C 2002/06/12 11:40:32 1.241 @@ -4,7 +4,7 @@ Copyright (c) 2001, 2002 ArtLebedev Group (http://www.artlebedev.com) Author: Alexandr Petrosian (http://paf.design.ru) - $Id: execute.C,v 1.237 2002/04/18 11:41:29 paf Exp $ + $Id: execute.C,v 1.241 2002/06/12 11:40:32 paf Exp $ */ #include "pa_opcode.h" @@ -111,6 +111,49 @@ void debug_dump(Pool& pool, int level, c #define POP_NAME() static_cast(stack.pop())->as_string() #define POP_CODE() static_cast(stack.pop()) +/** + Helps preventing evaluation of junctions in outdated context + + To stop situations like this: +@code + @main[] + ^method1[] + ^method2[] + + @method1[] + $junction{ + some code + } + + @method2[] + ^junction[] +@endcode + + All Junctions, generated by OP_CURLY_CODE__CONSTRUCT are registered here, + and on scope exit got cleaned - there Junction::root becomes 0, + which later in Request::process triggers exception +*/ +class Auto_junction_cleaner { +public: + Auto_junction_cleaner () : junctions(0) {} + ~Auto_junction_cleaner () { + if(junctions) { + Array_iter i(*junctions); + while(i.has_next()) + static_cast(i.next())->change_context(0); + // someday free junctions + } + } + void register_junction(Pool& apool, Junction& ajunction) { + if(!junctions) + junctions=new(apool) Array(apool); + if(junctions) + *junctions+=&ajunction; + } +private: + Array *junctions; +}; + void Request::execute(const Array& ops) { // _asm int 3; #ifdef DEBUG_EXECUTE @@ -119,6 +162,7 @@ void Request::execute(const Array& ops) debug_printf(pool(), "execution-------------------------\n"); #endif + Auto_junction_cleaner junction_cleaner; const String *last_get_element_name=0; Array_iter i(ops); @@ -214,7 +258,8 @@ void Request::execute(const Array& ops) rcontext, wcontext, local_ops); - + junction_cleaner.register_junction(pool(), j); + value=NEW VJunction(j); const String& name=POP_NAME(); Value *ncontext=POP(); @@ -859,6 +904,12 @@ StringOrValue Request::process(Value& in #ifdef DEBUG_EXECUTE debug_printf(pool(), "ja->\n"); #endif + + if(!junction->root) + throw Exception("parser.runtime", + 0, + "junction used outside of context"); + PUSH(self); PUSH(root); PUSH(rcontext); @@ -910,8 +961,8 @@ StringOrValue Request::process(Value& in return result; } -const String *Request::execute_method(Value& aself, const Method& method, - bool return_cstr) { +void Request::execute_method(Value& aself, const Method& method, + const String **return_string) { PUSH(self); PUSH(root); PUSH(rcontext); @@ -927,20 +978,17 @@ const String *Request::execute_method(Va // result const String *result=0; - if(return_cstr) { + if(return_string) { if(Value *result_var_value=wcontext->get_element(*result_var_name)) - result=&result_var_value->as_string(); + *return_string=&result_var_value->as_string(); else - result=&wcontext->as_string(); + *return_string=&wcontext->as_string(); } wcontext=static_cast(POP()); rcontext=POP(); root=POP(); self=static_cast(POP()); - - // return - return result; } const String& Request::execute_method(VMethodFrame& amethodFrame, const Method& method) { @@ -972,17 +1020,25 @@ const String *Request::execute_virtual_m const String& method_name) { if(Value *value=aself.get_element(method_name)) if(Junction *junction=value->get_junction()) - if(const Method *method=junction->method) - return execute_method(aself, *method, true /*return_cstr*/); + if(const Method *method=junction->method) { + const String *result; + execute_method(aself, *method, &result); + return result; + } return 0; } -const String *Request::execute_nonvirtual_method(VStateless_class& aclass, +void Request::execute_nonvirtual_method(VStateless_class& aclass, const String& method_name, - bool return_cstr) { - if(const Method *method=aclass.get_method(method_name)) - return execute_method(aclass, *method, return_cstr); + const String **return_string, + const Method **return_method) { + const Method *method=aclass.get_method(method_name); + if(return_string) + *return_string=0; + if(return_method) + *return_method=method; - return 0; + if(method) + execute_method(aclass, *method, return_string); }