--- parser3/src/classes/op.C 2005/11/25 11:53:59 1.162 +++ parser3/src/classes/op.C 2007/04/23 10:30:09 1.166 @@ -5,7 +5,7 @@ Author: Alexandr Petrosian (http://paf.design.ru) */ -static const char * const IDENT_OP_C="$Date: 2005/11/25 11:53:59 $"; +static const char * const IDENT_OP_C="$Date: 2007/04/23 10:30:09 $"; #include "classes.h" #include "pa_vmethod_frame.h" @@ -38,10 +38,20 @@ public: VClassMAIN(); }; +// defines for globals + +#define CYCLE_DATA_NAME "CYCLE-DATA" + +// globals + +//^for & co +String cycle_data_name(CYCLE_DATA_NAME); + // defines for statics #define SWITCH_DATA_NAME "SWITCH-DATA" #define CACHE_DATA_NAME "CACHE-DATA" + #define EXCEPTION_VAR_NAME "exception" // statics @@ -53,6 +63,7 @@ static const String cache_data_name(CACH static const String exception_var_name(EXCEPTION_VAR_NAME); + // local defines #define CACHE_EXCEPTION_HANDLED_CACHE_NAME "cache" @@ -152,7 +163,7 @@ static void _process(Request& r, MethodP { VStateless_class *target_class=target_self->get_last_derived_class(); if(!target_class) - throw Exception("parser.runtime", + throw Exception(PARSER_RUNTIME, 0, "no target class"); @@ -169,7 +180,7 @@ static void _process(Request& r, MethodP Value& voptions=params.as_no_junction(options_index, "options must not be code"); options=voptions.get_hash(); if(!options) - throw Exception("parser.runtime", + throw Exception(PARSER_RUNTIME, 0, "options must be hash"); } @@ -193,7 +204,7 @@ static void _process(Request& r, MethodP } if(valid_options!=options->count()) - throw Exception("parser.runtime", + throw Exception(PARSER_RUNTIME, 0, "called with invalid option"); } @@ -229,6 +240,9 @@ static void _rem(Request&, MethodParams& } static void _while(Request& r, MethodParams& params) { + Temp_hash_value + cycle_data_setter(r.classes_conf, cycle_data_name, /*any not null flag*/&r); + Value& vcondition=params.as_junction(0, "condition must be expression"); Value& body_code=params.as_junction(1, "body must be code"); Value* delim_maybe_code=params.count()>2?¶ms[2]:0; @@ -238,7 +252,7 @@ static void _while(Request& r, MethodPar bool need_delim=false; while(true) { if(++endless_loop_count>=MAX_LOOPS) // endless loop? - throw Exception("parser.runtime", + throw Exception(PARSER_RUNTIME, 0, "endless loop detected"); @@ -248,6 +262,7 @@ static void _while(Request& r, MethodPar break; StringOrValue sv_processed=r.process(body_code); + Request::Skip lskip=r.get_skip(); r.set_skip(Request::SKIP_NOTHING); const String* s_processed=sv_processed.get_string(); if(delim_maybe_code && s_processed && s_processed->length()) { // delimiter set and we have body if(need_delim) // need delim & iteration produced string? @@ -255,6 +270,9 @@ static void _while(Request& r, MethodPar need_delim=true; } r.write_pass_lang(sv_processed); + + if(lskip==Request::SKIP_BREAK) + break; } } @@ -263,7 +281,28 @@ static void _use(Request& r, MethodParam r.use_file(r.main_class, vfile.as_string()); } +static void set_skip(Request& r, Request::Skip askip) { + void* data=r.classes_conf.get(cycle_data_name); + if(!data) + throw Exception(PARSER_RUNTIME, + 0, + "without cycle"); + + r.set_skip(askip); +} + +static void _break(Request& r, MethodParams&) { + set_skip(r, Request::SKIP_BREAK); +} + +static void _continue(Request& r, MethodParams&) { + set_skip(r, Request::SKIP_CONTINUE); +} + static void _for(Request& r, MethodParams& params) { + Temp_hash_value + cycle_data_setter(r.classes_conf, cycle_data_name, /*any not null flag*/&r); + const String& var_name=params.as_string(0, "var name must be string"); int from=params.as_int(1, "from must be int", r); int to=params.as_int(2, "to must be int", r); @@ -271,7 +310,7 @@ static void _for(Request& r, MethodParam Value* delim_maybe_code=params.count()>4?¶ms[4]:0; if(to-from>=MAX_LOOPS) // too long loop? - throw Exception("parser.runtime", + throw Exception(PARSER_RUNTIME, 0, "endless loop detected"); @@ -284,6 +323,7 @@ static void _for(Request& r, MethodParam vint->set_int(i); StringOrValue sv_processed=r.process(body_code); + Request::Skip lskip=r.get_skip(); r.set_skip(Request::SKIP_NOTHING); const String* s_processed=sv_processed.get_string(); if(delim_maybe_code && s_processed && s_processed->length()) { // delimiter set and we have body if(need_delim) // need delim & iteration produced string? @@ -291,6 +331,9 @@ static void _for(Request& r, MethodParam need_delim=true; } r.write_pass_lang(sv_processed); + + if(lskip==Request::SKIP_BREAK) + break; } } @@ -298,7 +341,7 @@ static void _eval(Request& r, MethodPara Value& expr=params.as_junction(0, "need expression"); // evaluate expresion Value& value_result=r.process_to_value(expr, - true/*don't intercept string*/).as_expr_result(); + false/*don't intercept string*/).as_expr_result(); if(params.count()>1) { Value& fmt=params.as_no_junction(1, "fmt must not be code"); r.write_no_lang(String(format(value_result.as_double(), fmt.as_string().cstrm()))); @@ -380,13 +423,15 @@ static void _switch(Request& r, MethodPa static void _case(Request& r, MethodParams& params) { Switch_data* data=static_cast(r.classes_conf.get(switch_data_name)); if(!data) - throw Exception("parser.runtime", + throw Exception(PARSER_RUNTIME, 0, "without switch"); int count=params.count(); Value& code=params.as_junction(--count, "case result must be code"); + Value& searching=data->searching; + bool we_are_searching_string_or_void=searching.is_string() || searching.is_void(); for(int i=0; isearching.is_string()) - matches=data->searching.as_string() == value.as_string(); + if(we_are_searching_string_or_void) + matches=searching.as_string() == value.as_string(); else - matches=data->searching.as_double() == value.as_double(); + matches=searching.as_double() == value.as_double(); if(matches) { if(data->found) - throw Exception("parser.runtime", + throw Exception(PARSER_RUNTIME, 0, "duplicate found"); @@ -533,7 +578,7 @@ static void locked_process_and_cache_put assert(body_from_disk); info.processed_code=body_from_disk; } else - throw Exception("parser.runtime", + 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"'"); @@ -626,7 +671,7 @@ static void _cache(Request& r, MethodPar // return current expiration time Cache_scope* scope=static_cast(r.classes_conf.get(cache_data_name)); if(!scope) - throw Exception("parser.runtime", + throw Exception(PARSER_RUNTIME, 0, "expire-time get without cache"); r.write_no_lang(*new VDate(scope->expires)); @@ -645,7 +690,7 @@ static void _cache(Request& r, MethodPar // secods|expires date Cache_scope* scope=static_cast(r.classes_conf.get(cache_data_name)); if(!scope) - throw Exception("parser.runtime", + throw Exception(PARSER_RUNTIME, 0, "expire-time reducing instruction without cache"); @@ -655,7 +700,7 @@ static void _cache(Request& r, MethodPar return; } else if(params.count()<3) - throw Exception("parser.runtime", + throw Exception(PARSER_RUNTIME, 0, "invalid number of parameters"); @@ -742,7 +787,7 @@ static void _try_operator(Request& r, Me &catch_code); if(result.exception_should_be_handled) - throw Exception("parser.runtime", + throw Exception(PARSER_RUNTIME, result.exception_should_be_handled, "catch block must set $exception.handled to some boolean value, not string"); @@ -767,7 +812,7 @@ static void _throw_operator(Request&, Me source?source:0, "%s", comment?comment:""); } else - throw Exception("parser.runtime", + throw Exception(PARSER_RUNTIME, 0, "one-param version has hash param"); } else { @@ -823,6 +868,10 @@ VClassMAIN::VClassMAIN(): VClass() { // ^use[file] add_native_method("use", Method::CT_ANY, _use, 1, 1); + // ^break[] + add_native_method("break", Method::CT_ANY, _break, 0, 0); + // ^continue[] + add_native_method("continue", Method::CT_ANY, _continue, 0, 0); // ^for[i](from-number;to-number-inclusive){code}[delim] add_native_method("for", Method::CT_ANY, _for, 3+1, 3+1+1);