Diff for /parser3/src/classes/op.C between versions 1.133 and 1.153.2.2

version 1.133, 2003/10/21 04:45:18 version 1.153.2.2, 2005/07/27 10:57:52
Line 1 Line 1
 /** @file  /** @file
         Parser: parser @b operators.          Parser: parser @b operators.
   
         Copyright (c) 2001-2003 ArtLebedev Group (http://www.artlebedev.com)          Copyright (c) 2001-2004 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)
 */  */
   
 static const char* IDENT_OP_C="$Date$";  static const char * const IDENT_OP_C="$Date$";
   
 #include "classes.h"  #include "classes.h"
 #include "pa_vmethod_frame.h"  #include "pa_vmethod_frame.h"
   
 #include "pa_common.h"  #include "pa_common.h"
   #include "pa_os.h"
 #include "pa_request.h"  #include "pa_request.h"
 #include "pa_vint.h"  #include "pa_vint.h"
 #include "pa_sql_connection.h"  #include "pa_sql_connection.h"
 #include "pa_vdate.h"  #include "pa_vdate.h"
 #include "pa_vmethod_frame.h"  #include "pa_vmethod_frame.h"
 #include "pa_vclass.h"  #include "pa_vclass.h"
   #include "pa_charset.h"
   
 // limits  // limits
   
Line 25  static const char* IDENT_OP_C="$Date$"; Line 27  static const char* IDENT_OP_C="$Date$";
 // defines  // defines
   
 #define CASE_DEFAULT_VALUE "DEFAULT"  #define CASE_DEFAULT_VALUE "DEFAULT"
   #define PROCESS_MAIN_OPTION_NAME "main"
   #define PROCESS_FILE_OPTION_NAME "file"
   #define PROCESS_LINENO_OPTION_NAME "lineno"
   
 // class  // class
   
Line 48  static const String cache_data_name(CACH Line 53  static const String cache_data_name(CACH
   
 static const String exception_var_name(EXCEPTION_VAR_NAME);  static const String exception_var_name(EXCEPTION_VAR_NAME);
   
   // local defines
   
   #define CACHE_EXCEPTION_HANDLED_CACHE_NAME "cache"
   
 // helpers  // helpers
   
 class Untaint_lang_name2enum: public Hash<const String::Body, String::Language> {  class Untaint_lang_name2enum: public Hash<const String::Body, String::Language> {
Line 61  public: Line 70  public:
                 ULN("http-header", HTTP_HEADER);                  ULN("http-header", HTTP_HEADER);
                 ULN("mail-header", MAIL_HEADER);                  ULN("mail-header", MAIL_HEADER);
                 ULN("uri", URI);                  ULN("uri", URI);
                 ULN("table", TABLE);  
                 ULN("sql", SQL);                  ULN("sql", SQL);
                 ULN("js", JS);                  ULN("js", JS);
                 ULN("xml", XML);                  ULN("xml", XML);
Line 78  static void _if(Request& r, MethodParams Line 86  static void _if(Request& r, MethodParams
         Value& condition_code=params.as_junction(0, "condition must be expression");          Value& condition_code=params.as_junction(0, "condition must be expression");
   
         bool condition=r.process_to_value(condition_code,           bool condition=r.process_to_value(condition_code, 
                 /*0/*no name* /,*/  
                 false/*don't intercept string*/).as_bool();                  false/*don't intercept string*/).as_bool();
         if(condition)          if(condition)
                 r.write_pass_lang(r.process(params.as_junction(1, "'then' parameter must be code")));                  r.write_pass_lang(r.process(params.as_junction(1, "'then' parameter must be code")));
Line 158  static void _process(Request& r, MethodP Line 165  static void _process(Request& r, MethodP
                 // temporary zero @auto so it wouldn't be auto-called in Request::use_buf                  // temporary zero @auto so it wouldn't be auto-called in Request::use_buf
                 Temp_method temp_method_auto(*target_class, auto_method_name, 0);                  Temp_method temp_method_auto(*target_class, auto_method_name, 0);
   
                 size_t main_alias_index=index+1;                  size_t options_index=index+1;
                 const String* main_alias=0;                  HashStringValue* options=0;
                 if(main_alias_index<params.count())                  if(options_index<params.count()) {
                         main_alias=&params.as_string(main_alias_index, "main alias must be string");                          Value& voptions=params.as_no_junction(options_index, "options must not be code");
                           options=voptions.get_hash();
                           if(!options)
                                   throw Exception("parser.runtime",
                                           0,
                                           "options must be hash");
                   }
   
                 if(const String* file_name=params[index].get_string()) { // ^process...[file]                  const String* main_alias=0;
                         r.use_file(*target_class, r.absolute(*file_name), main_alias, true/*ignore_class_path*/);                  const String* file_alias=0;
                 } else { // process...{string}                  int line_no_alias_offset=0;
                         Value& vjunction=params.as_junction(index, "body must be code");                  if(options) {
                         // evaluate source to process                          int valid_options=0;
                         const String& source=r.process_to_string(vjunction);                          if(Value* vmain_alias=options->get(PROCESS_MAIN_OPTION_NAME)) {
                         r.use_buf(*target_class,                                  valid_options++;
                                 source.cstr(String::L_UNSPECIFIED, r.connection(false)),                                  main_alias=&vmain_alias->as_string();
                                 main_alias,                          }
                                 pseudo_file_no__process);                                         if(Value* vfile_alias=options->get(PROCESS_FILE_OPTION_NAME)) {
                                   valid_options++;
                                   file_alias=&vfile_alias->as_string();
                           }
                           if(Value* vline_no_alias_offset=options->get(PROCESS_LINENO_OPTION_NAME)) {
                                   valid_options++;
                                   line_no_alias_offset=vline_no_alias_offset->as_int();
                           }
           
                           if(valid_options!=options->count())
                                   throw Exception("parser.runtime",
                                           0,
                                           "called with invalid option");
                 }                  }
   
                   uint processe_file_no=file_alias?
                           r.register_file(r.absolute(*file_alias))
                           : pseudo_file_no__process;
                   // process...{string}
                   Value& vjunction=params.as_junction(index, "body must be code");
                   // evaluate source to process
                   const String& source=r.process_to_string(vjunction);
                   r.use_buf(*target_class,
                           source.cstr(String::L_UNSPECIFIED, r.connection(false)),
                           main_alias,
                           processe_file_no,
                           line_no_alias_offset);
   
                 // main_method                  // main_method
                 main_method=target_class->get_method(main_method_name);                  main_method=target_class->get_method(main_method_name);
         }          }
Line 188  static void _process(Request& r, MethodP Line 226  static void _process(Request& r, MethodP
         }          }
 }  }
                   
 static void _rem(Request& r, MethodParams& params) {  static void _rem(Request&, MethodParams& params) {
         params.as_junction(0, "body must be code");          params.as_junction(0, "body must be code");
 }  }
   
Line 205  static void _while(Request& r, MethodPar Line 243  static void _while(Request& r, MethodPar
                                 "endless loop detected");                                  "endless loop detected");
   
                 bool condition=r.process_to_value(vcondition,                   bool condition=r.process_to_value(vcondition, 
                                 /*0/*no name* /,*/  
                                 false/*don't intercept string*/).as_bool();                                  false/*don't intercept string*/).as_bool();
                 if(!condition) // ...condition is true                  if(!condition) // ...condition is true
                         break;                          break;
Line 234  static void _for(Request& r, MethodParam Line 271  static void _for(Request& r, MethodParam
   
         bool need_delim=false;          bool need_delim=false;
         VInt* vint=new VInt(0);          VInt* vint=new VInt(0);
         r.get_method_frame()->caller()->put_element(var_name, vint, false);  
           VMethodFrame& caller=*r.get_method_frame()->caller();
           caller.put_element(caller, var_name, vint);
         for(int i=from; i<=to; i++) {          for(int i=from; i<=to; i++) {
                 vint->set_int(i);                  vint->set_int(i);
   
Line 253  static void _eval(Request& r, MethodPara Line 292  static void _eval(Request& r, MethodPara
         Value& expr=params.as_junction(0, "need expression");          Value& expr=params.as_junction(0, "need expression");
         // evaluate expresion          // evaluate expresion
         Value& value_result=r.process_to_value(expr,           Value& value_result=r.process_to_value(expr, 
                 /*0/*no name YET* /,*/  
                 true/*don't intercept string*/).as_expr_result();                  true/*don't intercept string*/).as_expr_result();
         if(params.count()>1) {          if(params.count()>1) {
                 Value& fmt=params.as_no_junction(1, "fmt must not be code");                  Value& fmt=params.as_no_junction(1, "fmt must not be code");
Line 281  struct timeval mt[2]; Line 319  struct timeval mt[2];
 gettimeofday(&mt[0],NULL);  gettimeofday(&mt[0],NULL);
 #endif  #endif
         // connect          // connect
         SQL_Connection* connection=SQL_driver_manager.get_connection(url.as_string(),           SQL_Connection* connection=SQL_driver_manager->get_connection(url.as_string(), 
                 protocol2driver_and_client);                  protocol2driver_and_client,
                   r.charsets.source().NAME().cstr());
   
 #ifdef RESOURCES_DEBUG  #ifdef RESOURCES_DEBUG
 //measure:after connect  //measure:after connect
Line 321  public: Line 360  public:
 #endif  #endif
 static void _switch(Request& r, MethodParams& params) {  static void _switch(Request& r, MethodParams& params) {
         Switch_data* data=new Switch_data(r, r.process_to_value(params[0]));          Switch_data* data=new Switch_data(r, r.process_to_value(params[0]));
         Temp_hash_value<const String::Body, PA_Object*>           Temp_hash_value<const String::Body, void*> 
                 switch_data_setter(r.classes_conf, switch_data_name, data);                  switch_data_setter(r.classes_conf, switch_data_name, data);
   
         Value& cases_code=params.as_junction(1, "switch cases must be code");          Value& cases_code=params.as_junction(1, "switch cases must be code");
         // execution of found ^case[...]{code} must be in context of ^switch[...]{code}          // execution of found ^case[...]{code} must be in context of ^switch[...]{code}
         // because of stacked WWrapper used there as wcontext          // because of stacked WWrapper used there as wcontext
         r.process(cases_code, true/*intercept_string*/);          r.process(cases_code, true/*intercept_string*/);
         if(Value* selected_code=data->found? data->found: data->_default) {          if(Value* selected_code=data->found? data->found: data->_default)
                 // setting code context, would execute in ^switch[...]{>>context<<}  
                 //selected_code->get_junction()->change_context(cases_code.get_junction());  
                 r.write_pass_lang(r.process(*selected_code));                  r.write_pass_lang(r.process(*selected_code));
         }  
 }  }
   
 static void _case(Request& r, MethodParams& params) {  static void _case(Request& r, MethodParams& params) {
Line 345  static void _case(Request& r, MethodPara Line 381  static void _case(Request& r, MethodPara
         int count=params.count();          int count=params.count();
         Value& code=params.as_junction(--count, "case result must be code");          Value& code=params.as_junction(--count, "case result must be code");
                   
         // killing context for safety, would execute in ^switch[...]{>>context<<}  
         // reason: context is stacked, and it would become invalid afterwards  
         //code->get_junction()->change_context(0);  
   
         for(int i=0; i<count; i++) {          for(int i=0; i<count; i++) {
                 Value& value=r.process_to_value(params[i]);                  Value& value=r.process_to_value(params[i]);
   
Line 374  static void _case(Request& r, MethodPara Line 406  static void _case(Request& r, MethodPara
                 }                  }
         }          }
 }  }
   #ifndef DOXYGEN
   struct Try_catch_result {
           StringOrValue processed_code;
           const String* exception_should_be_handled;
   
           Try_catch_result(): exception_should_be_handled(0) {}
   };
   #endif
   
   /// used by ^try and ^cache, @returns $exception.handled[string] if any
   template<class I>
   static Try_catch_result try_catch(Request& r, 
                     StringOrValue body_code(Request&, I), I info, 
                     Value* catch_code) 
   {
           Try_catch_result result;
           if(!catch_code) {
                   result.processed_code=body_code(r, info);
                   return result;
           }
   
           // taking snapshot of try-context
           Request_context_saver try_context(r);
           try {
                   result.processed_code=body_code(r, info);
           } catch(const Exception& e) {
                   Request_context_saver throw_context(r); // taking snapshot of throw-context [stack trace contains error]
                   Request::Exception_details details=r.get_details(e);
                   try_context.restore(); // restoring try-context to perform catch-code
   
                   Junction* junction=catch_code->get_junction();
                   Value* method_frame=junction->method_frame;
                   Value* saved_exception_var_value=method_frame->get_element(exception_var_name, *method_frame, false);
                   VMethodFrame& frame=*junction->method_frame;
                   frame.put_element(frame, exception_var_name, &details.vhash);
                   result.processed_code=r.process(*catch_code);
                   
                   // retriving $exception.handled, restoring $exception var
                   Value* vhandled=details.vhash.hash().get(exception_handled_part_name);
                   frame.put_element(frame, exception_var_name, saved_exception_var_value);
   
                   bool bhandled=false;
                   if(vhandled) {
                           if(vhandled->is_string()) { // not simple $exception.handled(1/0)?
                                   result.exception_should_be_handled=vhandled->get_string(); // considering 'recovered' and let the caller recover
                                   return result;
                           }
   
                           bhandled=vhandled->as_bool();           
                   }
   
                   if(!bhandled) {
                           throw_context.restore(); // restoring throw-context [exception were not handled]
                           rethrow;
                   }
           }
           return result;
   }
   
 // cache--  // cache--
   
 // consts  // consts
   
 const int DATA_STRING_SERIALIZED_VERSION=0x0005;  const int DATA_STRING_SERIALIZED_VERSION=0x0006;
   
 // helper types  // helper types
   
Line 395  void cache_delete(const String& file_spe Line 485  void cache_delete(const String& file_spe
 }  }
   
 #ifndef DOXYGEN  #ifndef DOXYGEN
 class Cache_data: public PA_Object {  struct Cache_scope {
 public:  public:
         time_t expires;          time_t expires;
           const String* body_from_disk;
 };  };
 struct Locked_process_and_cache_put_action_info {  struct Locked_process_and_cache_put_action_info {
         Request *r;          Request *r;
         Cache_data *data;          Cache_scope *scope;
         Value* body_code; const String* evaluated_body;          Value* body_code; Value* catch_code; 
           const String* processed_code;
 };  };
 #endif  #endif
   
   
   
   static StringOrValue process_cache_body_code(Request& r, Value* body_code) {
           return StringOrValue(r.process_to_string(*body_code));
   }
   
 /* @todo maybe network order worth spending some effort?  /* @todo maybe network order worth spending some effort?
         don't bothering myself with network byte order,          don't bothering myself with network byte order,
         am not planning to be able to move resulting file across platforms          am not planning to be able to move resulting file across platforms
Line 414  static void locked_process_and_cache_put Line 513  static void locked_process_and_cache_put
                 *static_cast<Locked_process_and_cache_put_action_info *>(context);                  *static_cast<Locked_process_and_cache_put_action_info *>(context);
   
         // body->process           // body->process 
         info.evaluated_body=&info.r->process_to_string(*info.body_code);          Try_catch_result result=try_catch(*info.r, 
                   process_cache_body_code, info.body_code,
                   info.catch_code);
   
           if(result.exception_should_be_handled) {
                   if(*result.exception_should_be_handled==CACHE_EXCEPTION_HANDLED_CACHE_NAME) {
                           if(const String* body_from_disk=info.scope->body_from_disk) // we have something old?
                                   info.processed_code=body_from_disk;
                           else
                                   throw Exception(0,
                                           new String("$"EXCEPTION_VAR_NAME"."EXCEPTION_HANDLED_PART_NAME"["CACHE_EXCEPTION_HANDLED_CACHE_NAME"]"),
                                           "fallback failed - there is no old cached body");
                   } else
                           throw Exception("parser.runtime",
                                   result.exception_should_be_handled,
                                   "$"EXCEPTION_VAR_NAME"."EXCEPTION_HANDLED_PART_NAME" value must be "
                                   "either boolean or string '"CACHE_EXCEPTION_HANDLED_CACHE_NAME"'");
           } else
                   info.processed_code=&result.processed_code.as_string();
   
         // expiration time not spoiled by ^cache(0) or something?          // expiration time not spoiled by ^cache(0) or something?
         if(info.data->expires > time(0)) {          if(info.scope->expires > time(0)) {
                 // string -serialize> buffer                  // string -serialize> buffer
                 String::Cm serialized=info.evaluated_body->serialize(                  String::Cm serialized=info.processed_code->serialize(
                         sizeof(Data_string_serialized_prolog));                          sizeof(Data_string_serialized_prolog));
                 Data_string_serialized_prolog& prolog=                  Data_string_serialized_prolog& prolog=
                         *reinterpret_cast<Data_string_serialized_prolog *>(serialized.str);                          *reinterpret_cast<Data_string_serialized_prolog *>(serialized.str);
                 prolog.version=DATA_STRING_SERIALIZED_VERSION;                  prolog.version=DATA_STRING_SERIALIZED_VERSION;
                 prolog.expires=info.data->expires;                  prolog.expires=info.scope->expires;
                                   
                 // buffer -write> file                  // buffer -write> file
                 write(f, serialized.str, serialized.length);                  write(f, serialized.str, serialized.length);
         } else // expired!          } else // expired!
                 info.data->expires=0; // flag it so that could be easily checked by caller                  info.scope->expires=0; // flag it so that could be easily checked by caller
 }  }
 const String* locked_process_and_cache_put(Request& r,   const String* locked_process_and_cache_put(Request& r, 
                                            Value& body_code,                                             Value& body_code,
                                            Cache_data& data,                                             Value* catch_code,
                                            const String& file_spec) {                                             Cache_scope& scope,
         Locked_process_and_cache_put_action_info info={0};                                             const String& file_spec) 
         info.r=&r;  {
         info.data=&data;          Locked_process_and_cache_put_action_info info={&r, &scope, &body_code, catch_code, 0};
         info.body_code=&body_code;  
   
         const String* result=file_write_action_under_lock(          const String* result=file_write_action_under_lock(
                 file_spec,                   file_spec, 
Line 446  const String* locked_process_and_cache_p Line 562  const String* locked_process_and_cache_p
                 false/*as_text*/,                  false/*as_text*/,
                 false/*do_append*/,                  false/*do_append*/,
                 false/*block*/,                  false/*block*/,
                 false/*fail on lock problem*/) ? info.evaluated_body: 0;                  false/*fail on lock problem*/) ? info.processed_code: 0;
         time_t now=time(0);          time_t now=time(0);
         if(data.expires<=now)          if(scope.expires<=now)
                 cache_delete(file_spec);                  cache_delete(file_spec);
         return result;          return result;
 }  }
 const String* cache_get(Request_charsets& charsets, const String& file_spec, time_t now) {  #ifndef DOXYGEN
   struct Cache_get_result {
           const String* body;
           bool expired;
   };
   #endif
   static Cache_get_result cache_get(Request_charsets& charsets, const String& file_spec, time_t now) {
           Cache_get_result result={0, false};
   
         File_read_result file=file_read(charsets, file_spec,           File_read_result file=file_read(charsets, file_spec, 
                            false/*as_text*/,                              false/*as_text*/, 
                            0, //no params                             0, //no params
Line 463  const String* cache_get(Request_charsets Line 587  const String* cache_get(Request_charsets
                 Data_string_serialized_prolog& prolog=                  Data_string_serialized_prolog& prolog=
                         *reinterpret_cast<Data_string_serialized_prolog *>(file.str);                          *reinterpret_cast<Data_string_serialized_prolog *>(file.str);
   
                 String* result=new String;                  String* body=new String;
                 if(                  if(
                         file.length>=sizeof(Data_string_serialized_prolog)                          file.length>=sizeof(Data_string_serialized_prolog)
                         && prolog.version==DATA_STRING_SERIALIZED_VERSION                          && prolog.version==DATA_STRING_SERIALIZED_VERSION) {
                         && prolog.expires > now                          if(body->deserialize(sizeof(Data_string_serialized_prolog),  file.str, file.length)) {
                         && result->deserialize(sizeof(Data_string_serialized_prolog),  file.str, file.length))                                  result.body=body;
                         return result;                                  result.expired=prolog.expires <= now;
                           }
                   }
         }          }
   
         return 0;          return result;
 }  }
 static time_t as_expires(Request& r, MethodParams& params,   static time_t as_expires(Request& r, MethodParams& params, 
                                                 int index, time_t now) {                                                  int index, time_t now) {
Line 498  static void _cache(Request& r, MethodPar Line 624  static void _cache(Request& r, MethodPar
                 }                  }
   
                 // secods|expires date                  // secods|expires date
                 Cache_data* data=static_cast<Cache_data*>(r.classes_conf.get(cache_data_name));                  Cache_scope* scope=static_cast<Cache_scope*>(r.classes_conf.get(cache_data_name));
                 if(!data)                  if(!scope)
                         throw Exception("parser.runtime",                          throw Exception("parser.runtime",
                                 0,                                  0,
                                 "expire-time reducing instruction without cache");                                  "expire-time reducing instruction without cache");
                                   
                 time_t expires=as_expires(r, params, 0, now);                  time_t expires=as_expires(r, params, 0, now);
                 if(expires < data->expires)                  if(expires < scope->expires)
                         data->expires=expires;                          scope->expires=expires;
   
                 return;                  return;
         }          } else if(params.count()<3)
                   throw Exception("parser.runtime",
                           0,
                           "invalid number of parameters"); 
                   
         // file_spec, expires, body code          // file_spec, expires, body code
         const String& file_spec=r.absolute(params.as_string(0, "filespec must be string"));          const String& file_spec=r.absolute(params.as_string(0, "filespec must be string"));
   
         Cache_data* data=new Cache_data;          Cache_scope scope={as_expires(r, params, 1, now), 0};
         Temp_hash_value<const String::Body, PA_Object*>   
                 cache_data_setter(r.classes_conf, cache_data_name, data);          Temp_hash_value<const String::Body, void*> 
         data->expires=as_expires(r, params, 1, now);                  cache_scope_setter(r.classes_conf, cache_data_name, &scope);
         Value& body_code=params.as_junction(2, "body must be code");          Value& body_code=params.as_junction(2, "body_code must be code");
           Value* catch_code=0;
           if(params.count()>3)
                   catch_code=&params.as_junction(3, "catch_code must be code");
   
         if(data->expires>now) { // valid 'expires' specified? try cached copy...          if(scope.expires>now) { // valid 'expires' specified? try cached copy...
                 // hence we don't hope to have unary create/lockEX                  // hence we don't hope to have unary create/lockEX
                 // we need some plan to live in a life like that, so...                   // we need some plan to live in a life like that, so... 
                 // worst races plan:                  // worst races plan:
Line 538  static void _cache(Request& r, MethodPar Line 670  static void _cache(Request& r, MethodPar
                 //          |lockSH succeeds; ...                  //          |lockSH succeeds; ...
   
                 for(int retry=0; retry<2; retry++) {                  for(int retry=0; retry<2; retry++) {
                         if(const String* cached_body=cache_get(r.charsets, file_spec, now)) { // have cached copy?                          Cache_get_result cached=cache_get(r.charsets, file_spec, now);
                                 // write it out                           if(cached.body) { // have cached copy
                                 r.write_assign_lang(*cached_body);                                  if(cached.expired) 
                                 // happy with it                                          scope.body_from_disk=cached.body; // storing for user to retrive it with ^cache[]
                                 return;                                  else // and it's not expired yet
                                   {
                                   // write it out 
                                   r.write_assign_lang(*cached.body);
                                   // happy with it
                                   return;
                           }
                         }                          }
   
                         // non-blocked lock; process; cache it                  // non-blocked lock; process; cache it
                         if(const String* processed_body=                  if(const String* processed_body=
                                 locked_process_and_cache_put(r, body_code, *data, file_spec)) {                          locked_process_and_cache_put(r, body_code, catch_code, scope, file_spec)) {
                                 // write it out                           // write it out 
                                 r.write_assign_lang(*processed_body);                          r.write_assign_lang(*processed_body);
                                 // happy with it                          // happy with it
                                 return;                          return;
                         } else { // somebody writing result right now                  } else { // somebody writing result right now
                                 pa_sleep(0, 500000); // waiting half a second                          pa_sleep(0, 500000); // waiting half a second
                                 retry=0; // prolonging our wait, than could cache_get it, without processing body_code                          retry=0; // prolonging our wait, than could cache_get it, without processing body_code
                         }                  }
                 }                  }
                 throw Exception(0,                  throw Exception(0,
                         &file_spec,                          &file_spec,
Line 573  static void _cache(Request& r, MethodPar Line 711  static void _cache(Request& r, MethodPar
         // never reached          // never reached
 }  }
   
   static StringOrValue process_try_body_code(Request& r, Value* body_code) {
           return r.process(*body_code);
 // also used in pa_request.C to pass param to @unhandled_exception  }
   
 static void _try_operator(Request& r, MethodParams& params) {  static void _try_operator(Request& r, MethodParams& params) {
         Value& body_code=params.as_junction(0, "body_code must be code");          Value& body_code=params.as_junction(0, "body_code must be code");
         Value& catch_code=params.as_junction(1, "catch_code must be code");          Value& catch_code=params.as_junction(1, "catch_code must be code");
   
         StringOrValue result;          Try_catch_result result=try_catch(r, 
         // taking snapshot of try-context                  process_try_body_code, &body_code,
         Request_context_saver try_context(r);                  &catch_code);
         try {          
                 result=r.process(body_code);          if(result.exception_should_be_handled)
         } catch(const Exception& e) {                  throw Exception("parser.runtime",
                 Request_context_saver throw_context(r); // taking snapshot of throw-context [stack trace contains error]                          result.exception_should_be_handled,
                 Request::Exception_details details=r.get_details(e);                          "catch block must set $exception.handled to some boolean value, not string");
                 try_context.restore(); // restoring try-context to perform catch-code  
   
                 Junction* junction=catch_code.get_junction();  
                 Value* method_frame=junction->method_frame;  
                 Value* saved_exception_var_value=method_frame->get_element(exception_var_name, *method_frame, false);  
                 junction->method_frame->put_element(exception_var_name, &details.vhash, false);  
                 result=r.process(catch_code);  
                 bool handled=false;  
                 if(Value* value=  
                         details.vhash.hash().get(exception_handled_part_name))  
                         handled=value->as_bool();                 
                 junction->method_frame->put_element(exception_var_name, saved_exception_var_value, false);  
   
                 if(!handled) {          // write out processed body_code or catch_code
                         throw_context.restore(); // restoring throw-context [exception were not handled]          r.write_pass_lang(result.processed_code);
                         rethrow;  
                 }  
         }  
         // write out result  
         r.write_pass_lang(result);  
 }  }
   
 static void _throw_operator(Request& r, MethodParams& params) {  static void _throw_operator(Request&, MethodParams& params) {
         if(params.count()==1) {          if(params.count()==1) {
                 if(HashStringValue *hash=params[0].get_hash()) {                  if(HashStringValue *hash=params[0].get_hash()) {
                         const char* type=0;                          const char* type=0;
Line 620  static void _throw_operator(Request& r, Line 740  static void _throw_operator(Request& r,
                         const String* source=0;                          const String* source=0;
                         if(Value* value=hash->get(exception_source_part_name))                          if(Value* value=hash->get(exception_source_part_name))
                                 source=&value->as_string();                                  source=&value->as_string();
                         const char* comment;                          const char* comment=0;
                         if(Value* value=hash->get(exception_comment_part_name))                          if(Value* value=hash->get(exception_comment_part_name))
                                 comment=value->as_string().cstr();                                  comment=value->as_string().cstr();
   
Line 640  static void _throw_operator(Request& r, Line 760  static void _throw_operator(Request& r,
         }          }
  }   }
   
   static void _sleep_operator(Request& r, MethodParams& params) {
           double seconds=params.as_double(0, "seconds must be double", r);
           pa_sleep((int)trunc(seconds), (int)trunc(seconds*1000));
    }
   
 #if defined(WIN32) && defined(_DEBUG)  #if defined(WIN32) && defined(_DEBUG)
 #       define PA_BPT  #       define PA_BPT
 static void _bpt(Request& r, MethodParams& params) {  static void _bpt(Request&, MethodParams&) {
         _asm int 3;          _asm int 3;
 }  }
 #endif  #endif
Line 668  VClassMAIN::VClassMAIN(): VClass() { Line 793  VClassMAIN::VClassMAIN(): VClass() {
         add_native_method("taint", Method::CT_ANY, _taint, 1, 2);          add_native_method("taint", Method::CT_ANY, _taint, 1, 2);
   
         // ^process[code]          // ^process[code]
         add_native_method("process", Method::CT_ANY, _process, 1, 2);          add_native_method("process", Method::CT_ANY, _process, 1, 3);
   
         // ^rem{code}          // ^rem{code}
         add_native_method("rem", Method::CT_ANY, _rem, 1, 10000);          add_native_method("rem", Method::CT_ANY, _rem, 1, 10000);
Line 690  VClassMAIN::VClassMAIN(): VClass() { Line 815  VClassMAIN::VClassMAIN(): VClass() {
         add_native_method("connect", Method::CT_ANY, _connect, 2, 2);          add_native_method("connect", Method::CT_ANY, _connect, 2, 2);
   
   
           // ^cache[file_spec](time){code}[{catch code}] time=0 no cache
         // ^cache[file_spec] delete cache          // ^cache[file_spec] delete cache
         // ^cache[file_spec](time){code} time=0 no cache          add_native_method("cache", Method::CT_ANY, _cache, 1, 4);
         add_native_method("cache", Method::CT_ANY, _cache, 1, 3);  
                   
         // switch          // switch
   
Line 710  VClassMAIN::VClassMAIN(): VClass() { Line 835  VClassMAIN::VClassMAIN(): VClass() {
         // ^throw[type;source;comment]          // ^throw[type;source;comment]
         add_native_method("throw", Method::CT_ANY, _throw_operator, 1, 3);          add_native_method("throw", Method::CT_ANY, _throw_operator, 1, 3);
   
           add_native_method("sleep", Method::CT_ANY, _sleep_operator, 1, 1);
 }  }
   
 // constructor & configurator  // constructor & configurator

Removed from v.1.133  
changed lines
  Added in v.1.153.2.2


E-mail: