diff --git a/src/funinfo.h b/src/funinfo.h index a2f3206..242f61f 100755 --- a/src/funinfo.h +++ b/src/funinfo.h @@ -46,6 +46,16 @@ namespace Ezc { +/* + a variable +*/ +struct Var +{ + std::wstring str; // a string value + bool res; // a boolean value +}; + + /* a base class for your own function data class @@ -111,16 +121,19 @@ struct Stack // !! IMPROVE ME // the name is bad -// may it should be called Env (environment) +// may it should be called Env (environment) or FunEnv template struct FunInfo { + // a result consists of a string and a boolean value // output stream StreamType & out; + // return value from a user's function (default false if not set directly by the function) + bool res; // table of parameters // the table can be empty - std::vector & params; + std::vector & params; // the first parameter // you can always use it even if there are not any parameters (params is empty) @@ -158,12 +171,10 @@ struct FunInfo // for other statements than [for] this is always zero size_t iter; - // return value from a user's function (default false if not set directly by the function) - bool res; // arguments: output_stream, table_of_parameters, the_first_parameter FunInfo(StreamType & o, - std::vector & pars, + std::vector & pars, const std::wstring & first_par, const StreamType & input_stream, Stack & s) : out(o), params(pars), par(first_par), in(input_stream), stack(s) diff --git a/src/generator.h b/src/generator.h index 8aa2cd2..e3d3656 100755 --- a/src/generator.h +++ b/src/generator.h @@ -39,7 +39,6 @@ #ifndef headerfile_ezc_generator #define headerfile_ezc_generator -#include "vars.h" #include "blocks.h" #include "pattern.h" #include "functions.h" @@ -126,10 +125,18 @@ public: private: + + // variables set + typedef std::map Vars; + Vars vars; + + Var temp_var; + struct BlockStack { - std::vector args; + std::vector args; StreamType * out_stream; + bool was_return; }; std::vector block_stack_tab; @@ -150,23 +157,11 @@ private: Blocks * pblocks; Functions * pfunctions; - // variables set - Vars vars; - // output_tmp_stream is used when outputting to more than one stream // (first we output to output_tmp_stream and then the content is copied // to the correct streams) StreamType output_tmp_stream; - // local_temp_stream is used when there are nested function calls - // e.g.: [function1 [function2]] - // function2 will be redirected to local_temp_stream and the string - // will be copied to Item::function.par std::wstring object - StreamType local_temp_stream; - - - std::vector parameters; - // pointers to the output streams std::vector output_stream_tab; @@ -259,8 +254,6 @@ private: Item ** item_block); bool FindInVariables(const std::wstring & name, - typename Functions::UserFunction ** function, - Item ** item_block, std::wstring ** variable); bool Find(const Item::Function & item_fun, @@ -272,12 +265,12 @@ private: FunInfo & info); void CallFunction(typename Functions::UserFunction * function, - std::vector & params, - StreamType & out_stream, - const StreamType & in_stream); + std::vector & parameters, + StreamType & out_stream, + const StreamType & in_stream); bool CallBlock(Item & item_block, - std::vector & params, + std::vector & parameters, StreamType & out_stream); bool Call(Item::Function & item_fun, @@ -325,6 +318,7 @@ private: void MakeTextDefine(Item & item); void MakeTextFilter(Item & item); void MakeTextEzc(Item & item); + void MakeTextReturn(Item & item); void MakeText(Item & item); void MakeEzcStream(Item::Function & fun); @@ -729,7 +723,7 @@ void Generator::Generate() filter_index = 0; stack_index = 0; block_stack_index = 0; - vars.Clear(); + vars.clear(); if( ppattern ) { @@ -741,7 +735,8 @@ void Generator::Generate() if( output_stream_index.size() > 1 ) WriteTmpStreamToStreams(); - vars.Clear(); + vars.clear(); + temp_var.str.clear(); is_generator_working = false; } catch(...) @@ -794,7 +789,7 @@ bool Generator::FindInCache(const Item::Function & item_fun, Item ** item_block, std::wstring ** variable) { - if( item_fun.arg >=0 ) + if( item_fun.arg >= 0 ) { empty_argument.clear(); *variable = &empty_argument; @@ -805,7 +800,10 @@ bool Generator::FindInCache(const Item::Function & item_fun, BlockStack & block_stack = block_stack_tab[block_stack_index-1]; if( size_t(item_fun.arg) < block_stack.args.size() ) - *variable = &block_stack.args[item_fun.arg]; + { + *variable = &block_stack.args[item_fun.arg].str; + last_res = block_stack.args[item_fun.arg].res; + } } return true; @@ -864,26 +862,17 @@ return false; template bool Generator::FindInVariables(const std::wstring & name, - typename Functions::UserFunction ** function, - Item ** item_block, std::wstring ** variable) { - Vars::Iterator i = vars.Find(name); + Vars::iterator i = vars.find(name); - if( i != vars.End() ) + if( i != vars.end() ) { - Vars::Variable & var = i->second; + Var & var = i->second; - if( var.type == Vars::variable_string ) - { - *variable = &var.val; - return true; - } - else - { - // this is an alias to a function or to a block - return FindInFunctionsAndBlocks(var.val, function, item_block); - } + *variable = &var.str; + last_res = var.res; + return true; } return false; @@ -906,7 +895,7 @@ bool Generator::Find(const Item::Function & item_fun, if( FindInFunctionsAndBlocks(item_fun.name, function, item_block) ) return true; - if( FindInVariables(item_fun.name, function, item_block, variable) ) + if( FindInVariables(item_fun.name, variable) ) return true; CreateUnknownMsg(item_fun.name); @@ -937,26 +926,27 @@ void Generator::CallFunction(typename Functions::UserFun template void Generator::CallFunction(typename Functions::UserFunction * function, - std::vector & params, + std::vector & parameters, StreamType & out_stream, const StreamType & in_stream) { - if( params.empty() ) + if( parameters.empty() ) { - FunInfo info(out_stream, params, empty, in_stream, stack_tab[stack_index-1]); + FunInfo info(out_stream, parameters, empty, in_stream, stack_tab[stack_index-1]); CallFunction(function, info); } else { - FunInfo info(out_stream, params, params[0], in_stream, stack_tab[stack_index-1]); + FunInfo info(out_stream, parameters, parameters[0].str, in_stream, stack_tab[stack_index-1]); CallFunction(function, info); } } + template bool Generator::CallBlock(Item & item_block, - std::vector & params, + std::vector & parameters, StreamType & out_stream) { if( block_stack_index >= block_stack_tab.size() ) @@ -968,10 +958,8 @@ bool Generator::CallBlock(Item & item_block, StreamType * old_stream = output_stream; BlockStack & block_stack = block_stack_tab[block_stack_index]; - block_stack.args.resize(params.size()); - - for(size_t i=0 ; i::CallBlock(Item & item_block, #endif out_stream.write(str.c_str(), str.size()); - - last_res = !str.empty(); + // last_res is set by [return ...] statement ClearStream(*output_stream); output_stream = old_stream; @@ -1007,6 +994,7 @@ bool Generator::Call(Item::Function & item_fun, typename Functions::UserFunction * fun; Item * item_block; std::wstring * variable; +std::vector parameters; if( clear_out_stream ) ClearStream(out_stream); @@ -1014,57 +1002,40 @@ std::wstring * variable; if( !Find(item_fun, &fun, &item_block, &variable) ) return false; + parameters.resize(item_fun.parameters.size()); + for(size_t i=0 ; ipar; - - if( !item_fun.parameters[i]->name.empty() ) - item_fun.parameters[i]->par.clear(); + parameters[i].str = fun_child.par; + parameters[i].res = !fun_child.par.empty(); } } if( fun ) - { CallFunction(fun, parameters, out_stream, in_stream); - } else if( item_block ) - { return CallBlock(*item_block, parameters, out_stream); - } else if( variable ) - { out_stream.write(variable->c_str(), variable->size()); - last_res = !variable->empty(); - } return true; } @@ -1660,7 +1631,6 @@ void Generator::MakeTextFor(Item & item) // is_generating_for will be changed by next call to MakeText() // so we should set it in each iterations is_generating_for = true; - //Call(function, item.functions[0].params, stream_temp1, true, empty_stream); Call(item.functions[0], stream_temp1, true, empty_stream); if( !last_res ) @@ -1676,64 +1646,53 @@ void Generator::MakeTextFor(Item & item) template void Generator::MakeTextDefine(Item & item) { +Item::Function * pfun = 0; + if( !can_use_vars ) { CreateMsg(L"[def] statement not available"); return; } - + if( item.functions.size() == 1 && item.functions[0].parameters.size() == 1 ) { if( item.functions[0].parameters[0]->name.empty() ) { // it is [def name "string"] - vars.Insert(item.functions[0].name, Vars::variable_string, item.functions[0].parameters[0]->par); + temp_var.str = item.functions[0].parameters[0]->par; + temp_var.res = !temp_var.str.empty(); + vars[item.functions[0].name] = temp_var; } else { - // it is [def name [function]] - if( Call(*item.functions[0].parameters[0], stream_temp_define, true, empty_stream) ) - { - #ifdef EZC_HAS_SPECIAL_STREAM - const std::wstring & str = stream_temp_define.Str(); - #else - const std::wstring & str = stream_temp_define.str(); - #endif - - vars.Insert(item.functions[0].name, Vars::variable_string, str); - } + // it is [def name [function "funpar"]] + pfun = item.functions[0].parameters[0]; } } - else - if( item.functions.size() == 2 && - item.functions[0].parameters.empty() && - item.functions[1].parameters.empty() ) - { - typename Functions::UserFunction * function; - Item * item_block; - std::wstring * variable; - if( Find(item.functions[1], &function, &item_block, &variable) ) + if( item.functions.size() == 2 ) + { + // is is [def name function "funpar"] + pfun = &item.functions[1]; + } + + if( pfun ) + { + if( Call(*pfun, stream_temp_define, true, empty_stream) ) { - if( variable ) - { - Vars::Iterator i = vars.Find(*variable); + #ifdef EZC_HAS_SPECIAL_STREAM + temp_var.str = stream_temp_define.Str(); + #else + temp_var.str = stream_temp_define.str(); + #endif - if( i != vars.End() ) - { - Vars::Variable & var = i->second; - vars.Insert(*variable, var.type, var.val); - } - } - else - { - vars.Insert(item.functions[0].name, Vars::variable_alias, item.functions[1].name); - } + temp_var.res = last_res; + vars[item.functions[0].name] = temp_var; } else { - CreateMsg(L"[def] unknown function/block/variable", item.functions[1].name.c_str()); + CreateMsg(L"[def] unknown function/block/variable", pfun->name); } } } @@ -1853,6 +1812,29 @@ void Generator::MakeTextEzc(Item & item) } +template +void Generator::MakeTextReturn(Item & item) +{ + last_res = false; + + if( block_stack_index == 0 ) + { + // the [return] statement is not called from a [block] + CreateMsg(L"[return] should be called from a [block]"); + return; + } + + BlockStack & block_stack = block_stack_tab[block_stack_index - 1]; + block_stack.was_return = true; + + if( !item.functions.empty() ) + { + // output stream in [return] statement is ignored + // this Call() sets last_res which is used later when we return to CallBlock() + Call(item.functions[0], stream_temp1, false, empty_stream); + ClearStream(stream_temp1); + } +} template @@ -1860,21 +1842,29 @@ bool Generator::LimitAchieved() { if( break_generating ) return true; - - if( ++current_item > max_items ) + + if( current_item >= max_items ) { break_generating = true; CreateMsg(L"Generator exceeded allowed number of elements"); return true; } - - if( ++stack_index > stack_tab.size() ) + + if( stack_index >= stack_tab.size() ) { break_generating = true; CreateMsg(L"Generator exceeded the stack size"); return true; } + if( block_stack_index > 0 ) + { + BlockStack & block_stack = block_stack_tab[block_stack_index - 1]; + + if( block_stack.was_return ) + return true; + } + return false; } @@ -1885,6 +1875,8 @@ void Generator::MakeText(Item & item) if( LimitAchieved() ) return; + current_item += 1; + stack_index += 1; is_generating_for = false; is_generating_if = false; is_generating_is = false; @@ -1909,6 +1901,7 @@ void Generator::MakeText(Item & item) else if( item.type == Item::item_for ) MakeTextFor(item); else if( item.type == Item::item_filter ) MakeTextFilter(item); else if( item.type == Item::item_ezc ) MakeTextEzc(item); + else if( item.type == Item::item_return ) MakeTextReturn(item); else if( item.type == Item::item_err ) CreateMsg(L"a wrong directive"); diff --git a/src/item.h b/src/item.h index 36c4f43..b2edf93 100755 --- a/src/item.h +++ b/src/item.h @@ -57,15 +57,17 @@ struct Item item_none, item_container, item_text, item_normal, item_is, item_isno, item_if, item_ifno, item_ifany, item_ifone, item_ifanyno, item_ifoneno, item_ifindex, item_for, item_else, item_end, item_err, item_include, item_comment, item_def, item_filter, - item_ezc, item_block + item_ezc, item_block, item_return }; struct Function { - std::wstring name; // function name (can be empty, means there is no any function -- only a text parameter) - std::wstring par; // parameter - std::vector parameters; + std::wstring name; // function name (can be empty, means there is no any function -- only + // a text parameter and a boolean value) + std::wstring par; // string parameter + std::vector parameters; // if name is not empty then is is a function and can have 'parameters' + // if name is empty then parameters is empty too void * fun_cache; // only valid if name is not empty Item * item_block; int arg; // used if name is numeric (if no then is equal -1) diff --git a/src/patternparser.cpp b/src/patternparser.cpp index 0a35a16..aaf50ea 100755 --- a/src/patternparser.cpp +++ b/src/patternparser.cpp @@ -578,6 +578,7 @@ bool PatternParser::ReadFunction(Item::Function & function) if( !ReadName(function.name) ) return false; + // !! IMPROVE ME add skiping some white characters (at the beginning and at the end) if( IsPositiveNumber(function.name) ) function.arg = wcstol(function.name.c_str(), 0, 10); @@ -787,11 +788,11 @@ void PatternParser::ReadDirectiveDef(Item & item) } else if( item.functions.size() == 2 && - item.functions[0].parameters.empty() && item.functions[1].parameters.empty() ) + item.functions[0].parameters.empty() ) { - // it is an alias: + // it is: // [def name function] - // (name is an alias to a function, to a block or to an other variable) + // or [def name function "funpar1" "funpar2"] etc. item.type = Item::item_def; } @@ -814,6 +815,7 @@ void PatternParser::ReadDirectiveEzc(Item & item) ReadFunctions(item); } + void PatternParser::ReadDirectiveBlock(Item & item) { item.type = Item::item_block; @@ -825,6 +827,16 @@ void PatternParser::ReadDirectiveBlock(Item & item) } +void PatternParser::ReadDirectiveReturn(Item & item) +{ + item.type = Item::item_return; + ReadFunctions(item); + + // max one function + if( item.functions.size() > 1 ) + item.type = Item::item_err; +} + // user defined directive void PatternParser::ReadDirectiveNormal(const std::wstring & name, Item & item) @@ -868,6 +880,7 @@ std::wstring name; else if( name == L"filter" ) ReadDirectiveFilter(item); else if( name == L"ezc" ) ReadDirectiveEzc(item); else if( name == L"block" ) ReadDirectiveBlock(item); + else if( name == L"return" ) ReadDirectiveReturn(item); else if( name == L"#" ) ReadDirectiveComment(item); else ReadDirectiveNormal(name, item); @@ -1042,8 +1055,6 @@ void PatternParser::CreateTree(Item & item) if( pitem->type == Item::item_include ) CreateTreeReadInclude(*pitem); - - // item_def is ignored here } } diff --git a/src/patternparser.h b/src/patternparser.h index 7fa6258..e087cc6 100755 --- a/src/patternparser.h +++ b/src/patternparser.h @@ -180,6 +180,7 @@ private: void ReadDirectiveFilter(Item & item); void ReadDirectiveEzc(Item & item); void ReadDirectiveBlock(Item & item); + void ReadDirectiveReturn(Item & item); void ReadDirectiveNormal(const std::wstring & name, Item & item); void CreateTreeReadItemDirectiveCheckEnding(Item & item);