--- parser3/src/main/execute.C 2002/04/22 10:15:12 1.239 +++ parser3/src/main/execute.C 2002/04/22 10:32:30 1.240 @@ -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.239 2002/04/22 10:15:12 paf Exp $ + $Id: execute.C,v 1.240 2002/04/22 10:32:30 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); @@ -210,10 +254,11 @@ void Request::execute(const Array& ops) #endif Junction& j=*NEW Junction(pool(), *self, 0, 0, - 0, - 0, - 0, + root, + rcontext, + wcontext, local_ops); + junction_cleaner.register_junction(pool(), j); value=NEW VJunction(j); const String& name=POP_NAME(); @@ -860,28 +905,28 @@ StringOrValue Request::process(Value& in 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); PUSH(wcontext); - - WContext *jwcontext; + self=&junction->self; - if(junction->root) { - root=junction->root; - rcontext=junction->rcontext; - jwcontext=junction->wcontext; - } else - jwcontext=wcontext; + root=junction->root; + 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 && jwcontext; + bool using_code_frame=intercept_string && junction->wcontext; if(using_code_frame) { // almost plain wwrapper about junction wcontext, // BUT intercepts string writes - VCodeFrame local(pool(), *jwcontext); + VCodeFrame local(pool(), *junction->wcontext); wcontext=&local; // execute it