diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..e34073d --- /dev/null +++ b/.editorconfig @@ -0,0 +1,21 @@ +# EditorConfig +# https://editorconfig.org/ +# https://editorconfig-specification.readthedocs.io/ + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true + +# 4 space indentation +[*.{h,cpp,html,css,js,conf,txt}] +indent_style = tab +indent_size = 4 + +# Tab indentation (no size specified) +[Makefile] +indent_style = tab +indent_size = 4 diff --git a/src/Makefile.dep b/src/Makefile.dep index 1bcb86d..b6e23c4 100644 --- a/src/Makefile.dep +++ b/src/Makefile.dep @@ -1,8 +1,40 @@ # DO NOT DELETE -blocks.o: blocks.h item.h cache.h functions.h funinfo.h objects.h -cache.o: cache.h item.h functions.h funinfo.h objects.h blocks.h +blocks.o: blocks.h item.h cache.h functions.h ../../pikotools/src/utf8/utf8.h +blocks.o: ../../pikotools/src/textstream/stream.h +blocks.o: ../../pikotools/src/utf8/utf8_templates.h +blocks.o: ../../pikotools/src/utf8/utf8_private.h funinfo.h objects.h +cache.o: cache.h item.h functions.h ../../pikotools/src/utf8/utf8.h +cache.o: ../../pikotools/src/textstream/stream.h +cache.o: ../../pikotools/src/utf8/utf8_templates.h +cache.o: ../../pikotools/src/utf8/utf8_private.h funinfo.h objects.h blocks.h item.o: item.h -pattern.o: pattern.h item.h cache.h functions.h funinfo.h objects.h blocks.h +models.o: models.h +pattern.o: pattern.h item.h cache.h functions.h +pattern.o: ../../pikotools/src/utf8/utf8.h +pattern.o: ../../pikotools/src/textstream/stream.h +pattern.o: ../../pikotools/src/utf8/utf8_templates.h +pattern.o: ../../pikotools/src/utf8/utf8_private.h funinfo.h objects.h +pattern.o: blocks.h patternparser.o: patternparser.h blocks.h item.h cache.h functions.h -patternparser.o: funinfo.h objects.h pattern.h +patternparser.o: ../../pikotools/src/utf8/utf8.h +patternparser.o: ../../pikotools/src/textstream/stream.h +patternparser.o: ../../pikotools/src/utf8/utf8_templates.h +patternparser.o: ../../pikotools/src/utf8/utf8_private.h funinfo.h objects.h +patternparser.o: pattern.h ../../pikotools/src/log/log.h +patternparser.o: ../../pikotools/src/textstream/textstream.h +patternparser.o: ../../pikotools/src/textstream/stream.h +patternparser.o: ../../pikotools/src/space/space.h +patternparser.o: ../../pikotools/src/textstream/types.h +patternparser.o: ../../pikotools/src/convert/inttostr.h +patternparser.o: ../../pikotools/src/date/date.h +patternparser.o: ../../pikotools/src/membuffer/membuffer.h +patternparser.o: ../../pikotools/src/textstream/types.h +patternparser.o: ../../pikotools/src/log/filelog.h +patternparser.o: ../../pikotools/src/convert/convert.h +patternparser.o: ../../pikotools/src/convert/inttostr.h +patternparser.o: ../../pikotools/src/convert/patternreplacer.h +patternparser.o: ../../pikotools/src/convert/strtoint.h +patternparser.o: ../../pikotools/src/convert/text.h +patternparser.o: ../../pikotools/src/convert/misc.h +patternparser.o: ../../pikotools/src/convert/double.h diff --git a/src/Makefile.o.dep b/src/Makefile.o.dep index 0bd4ba5..2f6a2c4 100644 --- a/src/Makefile.o.dep +++ b/src/Makefile.o.dep @@ -1 +1 @@ -o = blocks.o cache.o item.o pattern.o patternparser.o \ No newline at end of file +o = blocks.o cache.o item.o models.o pattern.o patternparser.o \ No newline at end of file diff --git a/src/funinfo.h b/src/funinfo.h index 18e5a44..606e9c0 100644 --- a/src/funinfo.h +++ b/src/funinfo.h @@ -172,9 +172,14 @@ struct FunInfo bool is_for; // indicates that this function is from [if ...] statement - // it is true for all kind of if's: if-one, if-any, if-no.... bool is_if; + // indicates that this function is from [if-def ...] statement + bool is_if_def; + + // indicates that this function is from [if-not-def ...] statement + bool is_if_not_def; + // indicates that this funcion is a normal statement e.g.: [funcion_name] bool is_normal; @@ -221,6 +226,8 @@ struct FunInfo res = false; // result is false by default is_for = false; is_if = false; + is_if_def = false; + is_if_not_def = false; is_normal = false; is_filter = false; iter = 0; diff --git a/src/generator.h b/src/generator.h index 9b49ed8..6c71d3d 100644 --- a/src/generator.h +++ b/src/generator.h @@ -39,17 +39,25 @@ #ifndef headerfile_ezc_generator #define headerfile_ezc_generator +#include +#include +#include #include "blocks.h" #include "pattern.h" #include "functions.h" #include "objects.h" #include "outstreams.h" -#include -#include -#include #include "expressionparser.h" +#include "models.h" +#include "log/log.h" +#include "utf8/utf8.h" + +#ifdef EZC_HAS_MORM_LIBRARY +#include "model.h" +#endif + namespace Ezc { @@ -75,6 +83,11 @@ public: void SetObjects(Objects & objects); void SetVariables(Vars & variables); // [def] and [let] + void SetLogger(pt::Log & logger); + +#ifdef EZC_HAS_MORM_LIBRARY + void SetModels(Models & models); +#endif void SetMax(size_t max_items_, size_t max_for_items_); @@ -124,14 +137,43 @@ public: void Generate(OutStreams & out_streams); - void SetCommentary(const char * com_start, const char * com_stop); - void SetCommentary(const std::string & com_start, const std::string & com_stop); - void SetCommentary(const wchar_t * com_start, const wchar_t * com_stop); - void SetCommentary(const std::wstring & com_start, const std::wstring & com_stop); private: + struct FindHelper + { + std::wstring * fun_name; + + BaseObj * base_obj; + int method_index; + typename Functions::UserFunction * function; + Item * item_block; + Var * variable; + + #ifdef EZC_HAS_MORM_LIBRARY + morm::Wrapper * wrapper; + size_t field_index; + #endif + + FindHelper() + { + fun_name = nullptr; + + base_obj = nullptr; + method_index = -1; + function = nullptr; + item_block = nullptr; + variable = nullptr; + +#ifdef EZC_HAS_MORM_LIBRARY + wrapper = nullptr; + field_index = 0; +#endif + } + }; + + struct BlockStack { std::vector args; @@ -151,7 +193,12 @@ private: Blocks * pblocks; Functions * pfunctions; Objects * pobjects; - Vars * pvars; +#ifdef EZC_HAS_MORM_LIBRARY + Models * pmodels; +#endif + Vars * pvars; + + pt::Log * plog; // pointer to the output streams map (can be null) // output stream will be created when [ezc frame "stream_name"] statement is found @@ -195,6 +242,8 @@ private: // true if the Generator is working with [for ...], [if ...] etc. bool is_generating_for; bool is_generating_if; + bool is_generating_if_def; + bool is_generating_if_not_def; bool is_generating_normal; bool is_generating_filter; @@ -205,8 +254,6 @@ private: // a stack for [for] statements std::vector stack_tab; - std::wstring commentary_start, commentary_stop; - bool can_use_vars; bool can_find_in_cache; bool program_mode; @@ -214,7 +261,6 @@ private: ExpressionParser * expression_parser; - void ResizeStreamStack(std::vector & stream_tab, size_t stream_tab_max_size); void ResizeFilterTab(); void ResizeStack(); @@ -228,6 +274,11 @@ private: void ClearEzcFrameTab(); void ClearStream(StreamType & str); + void CopyStreamToString(StreamType & src_stream, std::wstring & dst_string); + void CopyStream(StreamType & src_stream, StreamType & dst_stream); + void CopyStream(pt::WTextStream & src_stream, StreamType & dst_stream, bool should_escape); + + void RemoveStackFunData(Stack & sitem); bool ConvertToBool(const std::wstring & str); @@ -235,37 +286,25 @@ private: template CharType ToLower(CharType c); + bool IsTestingFunctionExistence(); - bool CheckBlockArgument(int arg_index, Var ** variable); + bool CheckBlockArgument(int arg_index, FindHelper & find_helper); - bool FindInCache(Item::Function & item_fun, - BaseObj ** base_obj, - int * method_index, - typename Functions::UserFunction ** function, - Item ** item_block); + bool FindInCache(Item::Function & item_fun, FindHelper & find_helper); - bool FindInFunctionsAndBlocks(const std::wstring & name, - BaseObj ** base_obj, - int * method_index, - typename Functions::UserFunction ** function, - Item ** item_block); - - bool FindInVariables(const std::wstring & name, - Var ** variable); +#ifdef EZC_HAS_MORM_LIBRARY + bool FindInModels(FindHelper & find_helper); +#endif + bool FindInFunctionsAndBlocks(const std::wstring & name, FindHelper & find_helper); + bool FindInVariables(const std::wstring & name, FindHelper & find_helper); + bool Find(Item::Function & item_fun, FindHelper & find_helper); - bool Find(Item::Function & item_fun, - std::wstring * fun_name, - BaseObj ** base_obj, - int * method_index, - typename Functions::UserFunction ** function, - Item ** item_block, - Var ** variable); + void PrepareEnvStruct(FunInfo & info); - void CallFunction(typename Functions::UserFunction * function, - FunInfo & info); + void CallFunction(typename Functions::UserFunction & function, FunInfo & info); - void CallFunction(typename Functions::UserFunction * function, + void CallFunction(typename Functions::UserFunction & function, std::vector & parameters, StreamType & out_stream, const StreamType & in_stream); @@ -274,18 +313,40 @@ private: std::vector & parameters, StreamType & out_stream); + void CallObject(BaseObj & base_obj, int method_index, FunInfo & info); - void CallObject(BaseObj * base_obj, int method_index, FunInfo & info); + void PrintDate(pt::Date * date, std::vector parameters, StreamType & out_stream); + bool PrintDatePart(pt::Date * date, const std::wstring & field, std::vector parameters, StreamType & out_stream); + bool CallDate(FindHelper & find_helper, std::vector & fields, std::vector parameters, StreamType & out_stream); - void CallObject(BaseObj * base_obj, + void PrintLastSpaceField(pt::Space * space, std::vector & parameters, StreamType & out_stream); + void CallSpaceObjectForLastField(std::vector & parameters, StreamType & out_stream, pt::Space * space); + pt::Space * CallSpaceObjectForMiddleField(std::wstring & root_space_name, std::vector & fields, size_t field_index, pt::Space * space); + + void CallSpaceTableForLastField(morm::SpaceWrapper & space_wrapper, std::vector & parameters, StreamType & out_stream, + pt::Space * space, size_t model_wrapper_space_table_index); + + pt::Space * CallSpaceTableForMiddleField(morm::SpaceWrapper & space_wrapper, std::wstring & root_space_name, std::vector & fields, + size_t field_index, pt::Space * space, size_t model_wrapper_space_table_index); + + bool CallSpace(FindHelper & find_helper, std::vector & fields, std::vector & parameters, StreamType & out_stream); + +#ifdef EZC_HAS_MORM_LIBRARY + bool CallModelField(morm::Model & model, const std::wstring & field, std::vector parameters, StreamType & out_stream, const StreamType & in_stream); + bool CallModel(morm::Model & model, FindHelper & find_helper, std::vector & fields, std::vector parameters, StreamType & out_stream, const StreamType & in_stream); + void FindLastModelWrapper(FindHelper & find_helper, std::vector & fields); + bool CallWrapper(FindHelper & find_helper, std::vector & fields, std::vector parameters, StreamType & out_stream, const StreamType & in_stream); +#endif + + void CallObject(BaseObj & base_obj, int method_index, std::vector & parameters, StreamType & out_stream, const StreamType & in_stream); bool CallVariable(Item::Function & item_fun, - Var * variable, + Var & variable, std::vector & parameters, StreamType & out_stream, const StreamType & in_stream); @@ -307,24 +368,40 @@ private: void SkipWhite(const wchar_t *& str); size_t StrToSize(const wchar_t * str, const wchar_t ** str_end = 0); + bool HasParam(std::vector & parameters, const wchar_t * param1, const wchar_t * param2 = nullptr); + bool ShouldMakeSpaceDump(std::vector & parameters); + bool ShouldMakeJsonDump(std::vector & parameters); + bool IsPrettyPrint(std::vector & parameters); + bool IsCurrentParam(std::vector & parameters); + + void DumpSpaceIfNeeded(std::vector & parameters, StreamType & out_stream, pt::Space * space); + void DumpModelIfNeeded(morm::Model & model, std::vector & parameters, StreamType & out_stream); + void CopyTmpStreamToOutputStreams(Item::Function & fun, StreamType & ezc_out_tmp_stream, StreamType & previous_stream); - void CreateMsg(std::wstring & out, const wchar_t * type, const wchar_t * arg = 0); - void CreateMsg(StreamType & stream, const wchar_t * type, const wchar_t * arg = 0); - void CreateMsg(const wchar_t * type, const wchar_t * arg = 0); + + void CreateMsg(const wchar_t * type, const std::wstring & model_name, std::vector & fields, size_t how_many_fields_print, + const wchar_t * arg = nullptr, const wchar_t * arg2 = nullptr, const wchar_t * arg3 = nullptr); + + void CreateMsg(const wchar_t * type, const std::wstring & model_name, std::vector & fields, + const wchar_t * arg = nullptr, const wchar_t * arg2 = nullptr, const wchar_t * arg3 = nullptr); + + void CreateMsg(const wchar_t * type, const wchar_t * arg = nullptr); void CreateMsg(const std::wstring & type, const std::wstring & arg); void CreateMsg(const std::wstring & type); - void CreateUnknownMsg(const std::wstring & fun); + bool LimitAchieved(); void EvaluateProgramNode(Item & item); void MakeTextIf_go(Item & item, bool result); void MakeTextIf(Item & item); + void MakeTextIfDef(Item & item); + void MakeTextIfNotDef(Item & item); void MakeTextFor(Item & item); void MakeItemText(Item & item); void MakeTextContainer(Item & item); - void MakeTextNormal(Item & item); + void MakeTextFunction(Item & item); void MakeTextDefine(Item & item, Var & var); void MakeTextDefine(Item & item); void MakeTextDefineIfNotSet(Item & item); @@ -351,11 +428,16 @@ private: template Generator::Generator() : empty_stream() { - ppattern = 0; - pblocks = 0; - pfunctions = 0; - pobjects = 0; - pvars = 0; + ppattern = nullptr; + pblocks = nullptr; + pfunctions = nullptr; + pobjects = nullptr; + pvars = nullptr; + plog = nullptr; + +#ifdef EZC_HAS_MORM_LIBRARY + pmodels = nullptr; +#endif max_items = 50000; max_for_items = 5000; @@ -390,6 +472,11 @@ Generator & Generator::operator=(const Generator::~Generator() } -template -void Generator::SetCommentary(const char * com_start, const char * com_stop) -{ - pt::utf8_to_wide(com_start, commentary_start); - pt::utf8_to_wide(com_stop, commentary_stop); -} - - - -template -void Generator::SetCommentary(const std::string & com_start, const std::string & com_stop) -{ - pt::utf8_to_wide(com_start, commentary_start); - pt::utf8_to_wide(com_stop, commentary_stop); -} - - - -template -void Generator::SetCommentary(const wchar_t * com_start, const wchar_t * com_stop) -{ - commentary_start = com_start; - commentary_stop = com_stop; -} - - - -template -void Generator::SetCommentary(const std::wstring & com_start, const std::wstring & com_stop) -{ - commentary_start = com_start; - commentary_stop = com_stop; -} - - template void Generator::SetPattern(Pattern & pattern) @@ -507,6 +559,22 @@ void Generator::SetVariables(Vars & variables) } +template +void Generator::SetLogger(pt::Log & logger) +{ + plog = &logger; +} + + + +#ifdef EZC_HAS_MORM_LIBRARY +template +void Generator::SetModels(Models & models) +{ + pmodels = ⊧ +} +#endif + template void Generator::CanUseCache(bool can_use_cache) { @@ -615,8 +683,6 @@ void Generator::ResizeBlockStack() - - template void Generator::ClearStreamStack(std::vector & stream_tab) { @@ -662,14 +728,91 @@ void Generator::ClearForStack() template void Generator::ClearStream(StreamType & str) { - #ifdef EZC_HAS_SPECIAL_STREAM - str.Clear(); + #ifdef EZC_GENERATOR_HAS_PT_STREAM + str.clear(); #else str.str(L""); #endif } + +template +void Generator::CopyStreamToString(StreamType & src_stream, std::wstring & dst_string) +{ + if constexpr (sizeof(wchar_t) == sizeof(typename StreamType::char_type)) + { + #ifdef EZC_GENERATOR_HAS_PT_STREAM + src_stream.to_str(dst_string); + #else + dst_string = src_stream.str(); + #endif + } + else + { + #ifdef EZC_GENERATOR_HAS_PT_STREAM + src_stream.to_str(dst_string); + #else + std::string tmp = src_stream.str(); + pt::utf8_to_wide(tmp, dst_string); + #endif + } +} + + +template +void Generator::CopyStream(StreamType & src_stream, StreamType & dst_stream) +{ + #ifdef EZC_GENERATOR_HAS_PT_STREAM + dst_stream << src_stream; + #else + dst_stream << src_stream.str(); + #endif +} + + +template +void Generator::CopyStream(pt::WTextStream & src_stream, StreamType & dst_stream, bool should_escape) +{ + if constexpr(sizeof(char) == sizeof(typename StreamType::char_type)) + { + // winix html stream is always wide (wchar_t) + // so if we are here then the dst_stream cannot be a Winix::HtmlTextStream + #ifndef EZC_GENERATOR_HAS_WINIX_STREAM + + wide_stream_to_utf8(src_stream, dst_stream, false); + + #endif + } + else + { + pt::WTextStream::iterator i = src_stream.begin(); + + while( i != src_stream.end() ) + { + #ifdef EZC_GENERATOR_HAS_WINIX_STREAM + + // IMPROVEME we need a better api from winix htmltextstream + + if( should_escape ) + { + dst_stream << *i; + } + else + { + dst_stream.write(&(*i), 1); + } + #else + dst_stream.write(&(*i), 1); + #endif + + ++i; + } + } +} + + + template void Generator::RemoveStackFunData(Stack & s) { @@ -817,9 +960,15 @@ void Generator::Generate(OutStreams & out_streams) } +template +bool Generator::IsTestingFunctionExistence() +{ + return is_generating_if_def || is_generating_if_not_def; +} + template -bool Generator::CheckBlockArgument(int arg_index, Var ** variable) +bool Generator::CheckBlockArgument(int arg_index, FindHelper & find_helper) { if( arg_index < 0 ) return false; @@ -831,7 +980,7 @@ bool Generator::CheckBlockArgument(int arg_index, Var ** variable) if( size_t(arg_index) < block_stack.args.size() ) { - *variable = &block_stack.args[arg_index]; + find_helper.variable = &block_stack.args[arg_index]; return true; } } @@ -842,30 +991,26 @@ bool Generator::CheckBlockArgument(int arg_index, Var ** variable) template -bool Generator::FindInCache(Item::Function & item_fun, - BaseObj ** base_obj, - int * method_index, - typename Functions::UserFunction ** function, - Item ** item_block) +bool Generator::FindInCache(Item::Function & item_fun, FindHelper & find_helper) { if( can_find_in_cache ) { if( item_fun.base_obj ) { - *base_obj = reinterpret_cast * >(item_fun.base_obj); - *method_index = item_fun.method_index; + find_helper.base_obj = reinterpret_cast * >(item_fun.base_obj); + find_helper.method_index = item_fun.method_index; return true; } if( item_fun.fun_cache ) { - *function = reinterpret_cast::UserFunction*>(item_fun.fun_cache); + find_helper.function = reinterpret_cast::UserFunction*>(item_fun.fun_cache); return true; } if( item_fun.item_block ) { - *item_block = item_fun.item_block; + find_helper.item_block = item_fun.item_block; return true; } } @@ -875,20 +1020,38 @@ return false; +#ifdef EZC_HAS_MORM_LIBRARY + template -bool Generator::FindInFunctionsAndBlocks(const std::wstring & name, - BaseObj ** base_obj, - int * method_index, - typename Functions::UserFunction ** function, - Item ** item_block) +bool Generator::FindInModels(FindHelper & find_helper) +{ + if( pmodels ) + { + morm::Wrapper * m = pmodels->Find(*find_helper.fun_name); + + if( m ) + { + find_helper.wrapper = m; + return true; + } + } + + return false; +} + +#endif + + +template +bool Generator::FindInFunctionsAndBlocks(const std::wstring & name, FindHelper & find_helper) { if( pobjects ) { - typename Objects::Iterator i = pobjects->Find(name, *method_index); + typename Objects::Iterator i = pobjects->Find(name, find_helper.method_index); if( i != pobjects->End() ) { - *base_obj = *i; + find_helper.base_obj = *i; return true; } } @@ -899,7 +1062,7 @@ bool Generator::FindInFunctionsAndBlocks(const std::wstring & name, if( i != pfunctions->End() ) { - *function = &i->second; + find_helper.function = &i->second; return true; } } @@ -910,7 +1073,7 @@ bool Generator::FindInFunctionsAndBlocks(const std::wstring & name, if( i != pblocks->End() ) { - *item_block = &i->second; + find_helper.item_block = &i->second; return true; } } @@ -920,8 +1083,7 @@ return false; template -bool Generator::FindInVariables(const std::wstring & name, - Var ** variable) +bool Generator::FindInVariables(const std::wstring & name, FindHelper & find_helper) { if( pvars ) { @@ -929,7 +1091,7 @@ bool Generator::FindInVariables(const std::wstring & name, if( i != pvars->end() ) { - *variable = &(i->second); + find_helper.variable = &(i->second); return true; } } @@ -938,127 +1100,718 @@ bool Generator::FindInVariables(const std::wstring & name, } + /* * fun_name can be null, it is used only with [let ...] statements * and if not null then means: as a funcion name we are not using item_fun.name but fun_name */ template -bool Generator::Find(Item::Function & item_fun, - std::wstring * fun_name, - BaseObj ** base_obj, - int * method_index, - typename Functions::UserFunction ** function, - Item ** item_block, - Var ** variable) +bool Generator::Find(Item::Function & item_fun, FindHelper & find_helper) { - *base_obj = nullptr; - *method_index = -1; - *function = nullptr; - *item_block = nullptr; - *variable = nullptr; + #ifdef EZC_HAS_MORM_LIBRARY + if( FindInModels(find_helper) ) + return true; - if( CheckBlockArgument(item_fun.arg, variable) ) + if( !item_fun.fields.empty() && !IsTestingFunctionExistence() ) + { + CreateMsg(L"unknown model", find_helper.fun_name->c_str()); + return false; + } + + #endif + + if( CheckBlockArgument(item_fun.arg, find_helper) ) return true; - if( FindInCache(item_fun, base_obj, method_index, function, item_block) ) + if( FindInCache(item_fun, find_helper) ) return true; - if( !fun_name ) - fun_name = &item_fun.name; - - if( FindInFunctionsAndBlocks(*fun_name, base_obj, method_index, function, item_block) ) + if( FindInFunctionsAndBlocks(*find_helper.fun_name, find_helper) ) return true; - if( FindInVariables(*fun_name, variable) ) + if( FindInVariables(*find_helper.fun_name, find_helper) ) return true; - CreateUnknownMsg(*fun_name); + if( !IsTestingFunctionExistence() ) + CreateMsg(L"unknown function", find_helper.fun_name->c_str()); -return false; + return false; +} + + +template +void Generator::PrepareEnvStruct(FunInfo & info) +{ + info.Clear(); + + info.is_for = is_generating_for; + info.is_if = is_generating_if; + info.is_if_def = is_generating_if_def; + info.is_if_not_def = is_generating_if_not_def; + info.is_normal = is_generating_normal; + info.is_filter = is_generating_filter; + info.iter = info.stack.iter; + info.stack_tab = stack_tab.data(); + info.stack_index = stack_index-1; } template -void Generator::CallFunction(typename Functions::UserFunction * function, FunInfo & info) +void Generator::CallFunction(typename Functions::UserFunction & function, FunInfo & info) { - info.Clear(); - - info.is_for = is_generating_for; - info.is_if = is_generating_if; - info.is_normal = is_generating_normal; - info.is_filter = is_generating_filter; - info.iter = info.stack.iter; - info.stack_tab = &stack_tab[0];//stack_tab.data();///////////////////////////////////////////////////////// - info.stack_index = stack_index-1; - - (*function)(info); - + PrepareEnvStruct(info); + (function)(info); last_res = info.res; } template -void Generator::CallFunction(typename Functions::UserFunction * function, +void Generator::CallFunction(typename Functions::UserFunction & function, std::vector & parameters, StreamType & out_stream, const StreamType & in_stream) { - if( parameters.empty() ) + if( !IsTestingFunctionExistence() ) { - FunInfo info(out_stream, parameters, empty, in_stream, stack_tab[stack_index-1], *stack_tab[stack_index-1].item); - CallFunction(function, info); - } - else - { - FunInfo info(out_stream, parameters, parameters[0].str, in_stream, stack_tab[stack_index-1], *stack_tab[stack_index-1].item); - CallFunction(function, info); + if( parameters.empty() ) + { + FunInfo info(out_stream, parameters, empty, in_stream, stack_tab[stack_index-1], *stack_tab[stack_index-1].item); + CallFunction(function, info); + } + else + { + FunInfo info(out_stream, parameters, parameters[0].str, in_stream, stack_tab[stack_index-1], *stack_tab[stack_index-1].item); + CallFunction(function, info); + } } } - - - template -void Generator::CallObject(BaseObj * base_obj, int method_index, FunInfo & info) +void Generator::CallObject(BaseObj & base_obj, int method_index, FunInfo & info) { - info.Clear(); - - info.is_for = is_generating_for; - info.is_if = is_generating_if; - info.is_normal = is_generating_normal; - info.is_filter = is_generating_filter; - info.iter = info.stack.iter; - info.stack_tab = &stack_tab[0];//stack_tab.data();///////////////////////////////////////////////////////// - info.stack_index = stack_index-1; - - base_obj->CallFun(method_index, info); - + PrepareEnvStruct(info); + base_obj.CallFun(method_index, info); last_res = info.res; } + template -void Generator::CallObject(BaseObj * base_obj, +bool Generator::HasParam(std::vector & parameters, const wchar_t * param1, const wchar_t * param2) +{ + for(Var & var : parameters) + { + if( !var.is_function ) + { + if( var.str == param1 || (param2 && var.str == param2) ) + { + return true; + } + } + } + + return false; +} + + + +template +bool Generator::ShouldMakeSpaceDump(std::vector & parameters) +{ + return HasParam(parameters, L"dump", L"dump_to_space"); +} + + +template +bool Generator::ShouldMakeJsonDump(std::vector & parameters) +{ + return HasParam(parameters, L"dump_to_json"); +} + + +template +bool Generator::IsCurrentParam(std::vector & parameters) +{ + return HasParam(parameters, L"current"); +} + + +template +bool Generator::IsPrettyPrint(std::vector & parameters) +{ + return HasParam(parameters, L"pretty"); +} + + + +template +void Generator::DumpSpaceIfNeeded(std::vector & parameters, StreamType & out_stream, pt::Space * space) +{ + bool dump_space = ShouldMakeSpaceDump(parameters); + bool dump_json = ShouldMakeJsonDump(parameters); + + if( dump_space || dump_json ) + { + bool pretty = IsPrettyPrint(parameters); + + if( dump_space ) + { + space->serialize_to_space_stream(out_stream, pretty); + } + else + if( dump_json ) + { + space->serialize_to_json_stream(out_stream, pretty); + } + } +} + + +template +void Generator::DumpModelIfNeeded(morm::Model & model, std::vector & parameters, StreamType & out_stream) +{ + bool dump_space = ShouldMakeSpaceDump(parameters); + bool dump_json = ShouldMakeJsonDump(parameters); + + if( dump_space || dump_json ) + { + //bool pretty = IsPrettyPrint(parameters); + + if( dump_space ) + { + // not implemented yet + } + else + if( dump_json ) + { + // IMPLEMENT ME + // depends on the model_connector (flat connector) + // need to be made in a different way + pt::TextStream temp_str; + model.to_text(temp_str, false, false); + out_stream << temp_str; + } + } +} + + + +template +void Generator::PrintDate(pt::Date * date, std::vector parameters, StreamType & out_stream) +{ + bool is_roman = HasParam(parameters, L"roman"); + bool is_no_sec = HasParam(parameters, L"no_sec"); + + date->Serialize(out_stream, is_roman, !is_no_sec); +} + + +template +bool Generator::PrintDatePart(pt::Date * date, const std::wstring & field, std::vector parameters, StreamType & out_stream) +{ + bool is_test = IsTestingFunctionExistence(); + + if( field == L"year" ) + { + if( !is_test ) + out_stream << date->year; + } + else + if( field == L"month" ) + { + if( !is_test ) + { + bool is_roman = HasParam(parameters, L"roman"); + + if( is_roman ) + pt::Date::SerializeMonthAsRoman(out_stream, date->month); + else + out_stream << date->month; + } + } + else + if( field == L"day" ) + { + if( !is_test ) + out_stream << date->day; + } + else + if( field == L"hour" ) + { + if( !is_test ) + out_stream << date->hour; + } + else + if( field == L"min" ) + { + if( !is_test ) + out_stream << date->min; + } + else + if( field == L"sec" ) + { + if( !is_test ) + out_stream << date->sec; + } + else + { + return false; + } + + return true; +} + + +template +bool Generator::CallDate(FindHelper & find_helper, std::vector & fields, std::vector parameters, StreamType & out_stream) +{ + bool found = true; + bool all_fields_known = (find_helper.field_index == fields.size()); + bool last_field_not_known = (find_helper.field_index + 1 == fields.size()); + + if( all_fields_known ) + { + PrintDate(find_helper.wrapper->date, parameters, out_stream); + } + else + if( last_field_not_known ) + { + if( !PrintDatePart(find_helper.wrapper->date, fields[find_helper.field_index], parameters, out_stream) ) + { + if( !IsTestingFunctionExistence() ) + { + CreateMsg(L"cannot find ", *find_helper.fun_name, fields, L", unknown property ", fields[find_helper.field_index].c_str(), L" of date object"); + } + + found = false; + } + } + else + { + if( !IsTestingFunctionExistence() ) + { + CreateMsg(L"cannot find ", *find_helper.fun_name, fields, L", ", fields[find_helper.field_index].c_str(), L" is not a model nor a model container nor a space"); + } + + found = false; + } + + return found; +} + + + + +template +void Generator::CallSpaceObjectForLastField(std::vector & parameters, StreamType & out_stream, pt::Space * space) +{ + if( !IsTestingFunctionExistence() ) + { + // CHECKME should we convert the last value to last_res? + DumpSpaceIfNeeded(parameters, out_stream, space); + } +} + + +template +pt::Space * Generator::CallSpaceObjectForMiddleField(std::wstring & root_space_name, std::vector & fields, size_t field_index, pt::Space * space) +{ + std::wstring & next_field = fields[field_index]; + space = space->get_space(next_field); + + if( !space && !IsTestingFunctionExistence() ) + { + CreateMsg(L"cannot find space field: ", root_space_name, fields, field_index + 1); + } + + return space; +} + + + +template +void Generator::CallSpaceTableForLastField(morm::SpaceWrapper & space_wrapper, std::vector & parameters, StreamType & out_stream, + pt::Space * space, size_t model_wrapper_space_table_index) +{ + pt::Space::TableType * table = space->get_table(); + + if( is_generating_for ) + { + // we are in [for...]statement, increment iterator and check the range + space_wrapper.increment_iterator(model_wrapper_space_table_index, table->size()); + size_t iterator_value = space_wrapper.get_space_iterator_value(model_wrapper_space_table_index); + last_res = (iterator_value < table->size()); + } + else + { + // we are not in [for..], it can be for example [if...], return true if the table is not empty + // if we are in [if-def...] - then last_res is set later in MakeTextIfDef(Item & item) when Call() method returns + last_res = !table->empty(); + } + + if( !IsTestingFunctionExistence() ) + { + DumpSpaceIfNeeded(parameters, out_stream, space); + + if( IsCurrentParam(parameters) ) + { + size_t iterator_value = space_wrapper.get_space_iterator_value(model_wrapper_space_table_index); + + if( iterator_value < table->size() ) + { + (*table)[iterator_value]->serialize_to_string(out_stream); + } + } + } +} + + +template +pt::Space * Generator::CallSpaceTableForMiddleField(morm::SpaceWrapper & space_wrapper, std::wstring & root_space_name, std::vector & fields, + size_t field_index, pt::Space * space, size_t model_wrapper_space_table_index) +{ + pt::Space::TableType * table = space->get_table(); + + // check the current iterator, if it is correct then select the item from the table + size_t iterator_value = space_wrapper.get_space_iterator_value(model_wrapper_space_table_index); + + if( iterator_value < table->size() ) + { + space = (*table)[iterator_value]; + } + else + { + // this message can be print even for [if-def...] + CreateMsg(L"space table: ", root_space_name, fields, field_index, L" is not initialized, have you forgotten to use [for...] statement?"); + space = nullptr; + } + + return space; +} + + +template +void Generator::PrintLastSpaceField(pt::Space * space, std::vector & parameters, StreamType & out_stream) +{ + bool no_escape = HasParam(parameters, L"raw", L"noescape"); + + if( no_escape ) + { + pt::WTextStream str; + space->serialize_to_string(str); + CopyStream(str, out_stream, false); + } + else + { + space->serialize_to_string(out_stream); + } +} + + + +template +bool Generator::CallSpace(FindHelper & find_helper, std::vector & fields, std::vector & parameters, StreamType & out_stream) +{ + morm::SpaceWrapper * space_wrapper = find_helper.wrapper->space_wrapper; + pt::Space * space = space_wrapper->get_space(); + last_res = false; + size_t field_index = find_helper.field_index; + + /* + * + * we are iterating through such objects: + * [root_space, fields[field_index], fields[field_index+1], fields[field_index+2], fields[field_index+3] ...] + * the first item is the root_space with a find_helper.fun_name name + * + */ + while( (field_index < fields.size() + 1) && space ) + { + bool is_last_field = (field_index == fields.size()); + + if( space->is_object() ) + { + if( is_last_field ) + { + CallSpaceObjectForLastField(parameters, out_stream, space); + } + else + { + space = CallSpaceObjectForMiddleField(*find_helper.fun_name, fields, field_index, space); + } + + field_index += 1; + } + else + if( space->is_table() ) + { + size_t model_wrapper_space_table_index = field_index - find_helper.field_index; + + if( model_wrapper_space_table_index < space_wrapper->space_indices_table_size() ) + { + if( is_last_field ) + { + CallSpaceTableForLastField(*space_wrapper, parameters, out_stream, space, model_wrapper_space_table_index); + field_index += 1; + } + else + { + space = CallSpaceTableForMiddleField(*space_wrapper, *find_helper.fun_name, fields, field_index, space, model_wrapper_space_table_index); + // don't increment field_index + } + } + else + { + CreateMsg(L"", *find_helper.fun_name, fields, field_index, L" exceeded the maximum number of fields for a space object"); + space = nullptr; + } + } + else + { + if( is_last_field ) + { + if( !IsTestingFunctionExistence() ) + { + PrintLastSpaceField(space, parameters, out_stream); + } + + field_index += 1; + } + else + { + if( !IsTestingFunctionExistence() ) + { + CreateMsg(L"", *find_helper.fun_name, fields, field_index, L" of a space is not an object nor a table"); + } + + space = nullptr; + } + } + } + + return space != nullptr; +} + + + +#ifdef EZC_HAS_MORM_LIBRARY + +template +bool Generator::CallModelField(morm::Model & model, const std::wstring & field, std::vector parameters, StreamType & out_stream, const StreamType & in_stream) +{ + /* + * if 'field' is a POD type then 'str' will be used in get_raw_value() + * if 'field' is a getter method with pt::Stream then 'str' will be used too + * if 'field' is a getter method which takes FunInfo<> then out_stream will be used and 'str' will be empty + * + */ + pt::WTextStream str; + bool found = false; + + if( parameters.empty() ) + { + FunInfo info(out_stream, parameters, empty, in_stream, stack_tab[stack_index-1], *stack_tab[stack_index-1].item); + found = model.get_raw_value(nullptr, field.c_str(), nullptr, info, str, false); + last_res = info.res; + } + else + { + FunInfo info(out_stream, parameters, parameters[0].str, in_stream, stack_tab[stack_index-1], *stack_tab[stack_index-1].item); + found = model.get_raw_value(nullptr, field.c_str(), nullptr, info, str, false); + last_res = info.res; + } + + if( found && !str.empty()) + { + bool no_escape = HasParam(parameters, L"raw", L"noescape"); + CopyStream(str, out_stream, !no_escape); + } + + return found; +} + + +template +bool Generator::CallModel(morm::Model & model, FindHelper & find_helper, std::vector & fields, + std::vector parameters, StreamType & out_stream, const StreamType & in_stream) +{ + bool found = true; + + if( find_helper.field_index == fields.size() ) + { + // all fields items are models or models containers + if( !IsTestingFunctionExistence() ) + { + DumpModelIfNeeded(model, parameters, out_stream); + } + } + else + if( find_helper.field_index + 1 == fields.size() ) + { + // last field is not a model nor a models container + if( !CallModelField(model, fields[find_helper.field_index], parameters, out_stream, in_stream) ) + { + if( !IsTestingFunctionExistence() ) + { + CreateMsg(L"cannot find ", *find_helper.fun_name, fields, L", unknown property ", fields[find_helper.field_index].c_str(), L" of a model object"); + } + + found = false; + } + } + else + { + if( !IsTestingFunctionExistence() ) + { + CreateMsg(L"cannot find ", *find_helper.fun_name, fields, L", ", fields[find_helper.field_index].c_str(), L" is not a model nor a model container nor a space"); + } + + found = false; + } + + return found; +} + + + +template +void Generator::FindLastModelWrapper(FindHelper & find_helper, std::vector & fields) +{ + for(find_helper.field_index = 0 ; find_helper.field_index < fields.size() && find_helper.wrapper->has_model_object() ; ++find_helper.field_index) + { + std::wstring & field = fields[find_helper.field_index]; + morm::Wrapper * child_wrapper = find_helper.wrapper->find_child(field); + + if( !child_wrapper ) + { + morm::Model * model = nullptr; + + if( find_helper.wrapper->model ) + { + model = find_helper.wrapper->model; + } + else + if( find_helper.wrapper->model_container_wrapper ) + { + model = find_helper.wrapper->model_container_wrapper->get_model(); + // this can return null for lists/vectors in a case when the iterator is not pointing to a valid item + } + + if( model ) + { + morm::Wrapper new_wrapper = model->get_wrapper(nullptr, field.c_str()); + + if( new_wrapper.has_object() ) + { + child_wrapper = find_helper.wrapper->add_child(field, new_wrapper); + } + } + } + + if( !child_wrapper ) + break; + + find_helper.wrapper = child_wrapper; + } +} + + +template +bool Generator::CallWrapper(FindHelper & find_helper, std::vector & fields, + std::vector parameters, StreamType & out_stream, const StreamType & in_stream) +{ + bool found = true; + last_res = false; + FindLastModelWrapper(find_helper, fields); + + // if: + // helper.field_index == fields.size() - all fields items are either models, models containers, space or a date + // helper.field_index == fields.size()-1 - only the last field is not known + // helper.field_index < fields.size()-1 - there are more not known fields + + bool all_fields_known = (find_helper.field_index == fields.size()); + bool last_field_not_known = (find_helper.field_index + 1 == fields.size()); + + if( find_helper.wrapper->space_wrapper ) + { + found = CallSpace(find_helper, fields, parameters, out_stream); + } + + if( find_helper.wrapper->date ) + { + found = CallDate(find_helper, fields, parameters, out_stream); + } + + if( find_helper.wrapper->model ) + { + found = CallModel(*find_helper.wrapper->model, find_helper, fields, parameters, out_stream, in_stream); + } + + if( find_helper.wrapper->model_container_wrapper ) + { + morm::Model * model = find_helper.wrapper->model_container_wrapper->get_model(); + + if( model ) + { + found = CallModel(*model, find_helper, fields, parameters, out_stream, in_stream); + } + else + { + if( last_field_not_known ) + { + // can be printed even for [if-def...] + CreateMsg(L"model ", *find_helper.fun_name, fields, L" is not initialized, have you forgotten to use [for ...] statement?"); + found = false; + } + } + + if( all_fields_known ) + { + if( is_generating_for ) + { + find_helper.wrapper->model_container_wrapper->increment_iterator(); + find_helper.wrapper->clear_childs(); + last_res = find_helper.wrapper->model_container_wrapper->is_iterator_correct(); + } + else + { + // for [if-def...] last_res will be set later + last_res = !find_helper.wrapper->model_container_wrapper->is_container_empty(); + } + } + } + + return found; +} + +#endif + + + +template +void Generator::CallObject(BaseObj & base_obj, int method_index, std::vector & parameters, StreamType & out_stream, const StreamType & in_stream) { - if( parameters.empty() ) + if( !IsTestingFunctionExistence() ) { - FunInfo info(out_stream, parameters, empty, in_stream, stack_tab[stack_index-1], *stack_tab[stack_index-1].item); - CallObject(base_obj, method_index, info); - } - else - { - FunInfo info(out_stream, parameters, parameters[0].str, in_stream, stack_tab[stack_index-1], *stack_tab[stack_index-1].item); - CallObject(base_obj, method_index, info); + if( parameters.empty() ) + { + FunInfo info(out_stream, parameters, empty, in_stream, stack_tab[stack_index-1], *stack_tab[stack_index-1].item); + CallObject(base_obj, method_index, info); + } + else + { + FunInfo info(out_stream, parameters, parameters[0].str, in_stream, stack_tab[stack_index-1], *stack_tab[stack_index-1].item); + CallObject(base_obj, method_index, info); + } } } @@ -1075,30 +1828,27 @@ bool Generator::CallBlock(Item & item_block, return false; } - StreamType * old_stream = output_stream; - BlockStack & block_stack = block_stack_tab[block_stack_index]; + if( !IsTestingFunctionExistence() ) + { + StreamType * old_stream = output_stream; + BlockStack & block_stack = block_stack_tab[block_stack_index]; - block_stack.was_return = false; - block_stack.args = parameters; + block_stack.was_return = false; + block_stack.args = parameters; - output_stream = block_stack.out_stream; - ClearStream(*output_stream); - block_stack_index += 1; + output_stream = block_stack.out_stream; + ClearStream(*output_stream); + block_stack_index += 1; - MakeText(item_block); + MakeText(item_block); - #ifdef EZC_HAS_SPECIAL_STREAM - const std::wstring & str = output_stream->Str(); - #else - const std::wstring & str = output_stream->str(); - #endif + CopyStream(*output_stream, out_stream); + // last_res is set by [return ...] statement or other last evaluated function - out_stream.write(str.c_str(), str.size()); - // last_res is set by [return ...] statement or other last evaluated function - - ClearStream(*output_stream); - output_stream = old_stream; - block_stack_index -= 1; + ClearStream(*output_stream); + output_stream = old_stream; + block_stack_index -= 1; + } return true; } @@ -1106,16 +1856,20 @@ return true; template -bool Generator::CallVariable(Item::Function & item_fun, Var * variable, std::vector & parameters, StreamType & out_stream, const StreamType & in_stream) +bool Generator::CallVariable(Item::Function & item_fun, Var & variable, std::vector & parameters, StreamType & out_stream, const StreamType & in_stream) { - if( variable->is_function ) + if( variable.is_function ) { - return Call(item_fun, &variable->str, out_stream, false, in_stream); + return Call(item_fun, &variable.str, out_stream, false, in_stream); } else { - out_stream << variable->str; - last_res = variable->res; + if( !IsTestingFunctionExistence() ) + { + out_stream << variable.str; + last_res = variable.res; + } + return true; } } @@ -1134,17 +1888,18 @@ bool Generator::Call(Item::Function & item_fun, bool clear_out_stream, const StreamType & in_stream) { -BaseObj * base_obj; -int method_index; -typename Functions::UserFunction * fun; -Item * item_block; -Var * variable; +FindHelper find_helper; std::vector parameters; if( clear_out_stream ) ClearStream(out_stream); - if( !Find(item_fun, fun_name, &base_obj, &method_index, &fun, &item_block, &variable) ) + find_helper.fun_name = fun_name; + + if( !find_helper.fun_name ) + find_helper.fun_name = &item_fun.name; + + if( !Find(item_fun, find_helper) ) return false; parameters.resize(item_fun.parameters.size()); @@ -1158,12 +1913,7 @@ std::vector parameters; StreamType local_temp_stream; Call(fun_child, nullptr, local_temp_stream, true, empty_stream); - #ifdef EZC_HAS_SPECIAL_STREAM - parameters[i].str = local_temp_stream.Str(); - #else - parameters[i].str = local_temp_stream.str(); - #endif - + CopyStreamToString(local_temp_stream, parameters[i].str); parameters[i].res = last_res; } else @@ -1173,17 +1923,22 @@ std::vector parameters; } } - if( base_obj ) - CallObject(base_obj, method_index, parameters, out_stream, in_stream); +#ifdef EZC_HAS_MORM_LIBRARY + if( find_helper.wrapper ) + return CallWrapper(find_helper, item_fun.fields, parameters, out_stream, in_stream); else - if( fun ) - CallFunction(fun, parameters, out_stream, in_stream); +#endif + if( find_helper.base_obj ) + CallObject(*find_helper.base_obj, find_helper.method_index, parameters, out_stream, in_stream); else - if( item_block ) - return CallBlock(*item_block, parameters, out_stream); + if( find_helper.function ) + CallFunction(*find_helper.function, parameters, out_stream, in_stream); else - if( variable ) - return CallVariable(item_fun, variable, parameters, out_stream, in_stream); + if( find_helper.item_block ) + return CallBlock(*find_helper.item_block, parameters, out_stream); + else + if( find_helper.variable ) + return CallVariable(item_fun, *find_helper.variable, parameters, out_stream, in_stream); return true; } @@ -1382,79 +2137,97 @@ void Generator::CopyTmpStreamToOutputStreams(Item::Function & fun, S { if( output_frames_streams ) { - #ifdef EZC_HAS_SPECIAL_STREAM - const std::wstring & str = ezc_out_tmp_stream.Str(); - #else - const std::wstring & str = ezc_out_tmp_stream.str(); - #endif + CopyStream(ezc_out_tmp_stream, previous_stream); - if( !str.empty() ) + for(size_t s=0 ; s < fun.parameters.size() ; ++s) { - previous_stream.write(str.c_str(), str.size()); + std::wstring & name = fun.parameters[s]->name; + auto imap = output_frames_streams->streams_map.find(name); - for(size_t s=0 ; s < fun.parameters.size() ; ++s) + if( imap == output_frames_streams->streams_map.end() ) { - std::wstring & name = fun.parameters[s]->name; - auto imap = output_frames_streams->streams_map.find(name); - - if( imap == output_frames_streams->streams_map.end() ) + if( output_frames_streams->streams_map.size() < output_frames_streams->streams_tab.size() ) { - if( output_frames_streams->streams_map.size() < output_frames_streams->streams_tab.size() ) - { - /* a new stream from the pool (output_stream_tab) is taken */ - StreamType * stream = output_frames_streams->streams_tab[ output_frames_streams->streams_map.size() ]; - output_frames_streams->streams_map.insert(std::make_pair(name, stream)); - ClearStream(*stream); - stream->write(str.c_str(), str.size()); - } - else - { - CreateMsg(previous_stream, L"limit of output streams in OutStreams<> has been reached"); - } + /* a new stream from the pool (output_stream_tab) is taken */ + StreamType * stream = output_frames_streams->streams_tab[ output_frames_streams->streams_map.size() ]; + output_frames_streams->streams_map.insert(std::make_pair(name, stream)); + ClearStream(*stream); + CopyStream(ezc_out_tmp_stream, *stream); } else { - StreamType * stream = imap->second; - stream->write(str.c_str(), str.size()); + CreateMsg(L"limit of output streams in OutStreams<> has been reached"); } } + else + { + StreamType * stream = imap->second; + CopyStream(ezc_out_tmp_stream, *stream); + } } } } -template -void Generator::CreateMsg(std::wstring & out, const wchar_t * type, const wchar_t * arg) -{ - out = commentary_start; - out += L"Ezc runtime error: "; - out += type; - - if( arg ) - { - out += ' '; - out += arg; - } - - out += commentary_stop; -} - - -template -void Generator::CreateMsg(StreamType & stream, const wchar_t * type, const wchar_t * arg) -{ - CreateMsg(temp_msg, type, arg); - stream.write(temp_msg.c_str(), temp_msg.size()); - temp_msg.clear(); -} - template void Generator::CreateMsg(const wchar_t * type, const wchar_t * arg) { - if( output_stream ) - CreateMsg(*output_stream, type, arg); + if( plog ) + { + (*plog) << pt::Log::log2 << "Ezc: " << type; + + if( arg ) + { + (*plog) << ' ' << arg; + } + + (*plog) << pt::Log::logend; + } +} + + + +template +void Generator::CreateMsg(const wchar_t * type, const std::wstring & model_name, std::vector & fields, size_t how_many_fields_print, + const wchar_t * arg, const wchar_t * arg2, const wchar_t * arg3) +{ + if( plog ) + { + (*plog) << pt::Log::log2 << L"Ezc: " << type << model_name; + + for(size_t i=0 ; i < how_many_fields_print && i < fields.size() ; ++i) + { + (*plog) << '.' << fields[i]; + } + + if( arg ) + { + (*plog) << arg; + } + + if( arg2 ) + { + (*plog) << arg2; + } + + if( arg3 ) + { + (*plog) << arg3; + } + + (*plog) << pt::Log::logend; + } +} + + +template +void Generator::CreateMsg(const wchar_t * type, const std::wstring & model_name, std::vector & fields, + const wchar_t * arg, const wchar_t * arg2, const wchar_t * arg3) +{ + + CreateMsg(type, model_name, fields, fields.size(), arg, arg2, arg3); } @@ -1474,13 +2247,6 @@ void Generator::CreateMsg(const std::wstring & type) } -template -void Generator::CreateUnknownMsg(const std::wstring & fun) -{ - CreateMsg(L"unknown function", fun.c_str()); -} - - template void Generator::EvaluateProgramNode(Item & item) @@ -1555,7 +2321,7 @@ void Generator::MakeTextContainer(Item & item) template -void Generator::MakeTextNormal(Item & item) +void Generator::MakeTextFunction(Item & item) { is_generating_normal = true; @@ -1616,6 +2382,42 @@ void Generator::MakeTextIf(Item & item) } +template +void Generator::MakeTextIfDef(Item & item) +{ + is_generating_if_def = true; + + if( program_mode ) + { + //CHECKME + //EvaluateProgramNode(item); + } + else + { + last_res = Call(item.function); + } + + MakeTextIf_go(item, last_res); +} + + +template +void Generator::MakeTextIfNotDef(Item & item) +{ + is_generating_if_not_def = true; + + if( program_mode ) + { + //CHECKME + //EvaluateProgramNode(item); + } + else + { + last_res = !Call(item.function); + } + + MakeTextIf_go(item, last_res); +} template @@ -1679,12 +2481,7 @@ void Generator::MakeTextDefine(Item & item, Var & var) // call function if( Call(fun, nullptr, stream_temp_define, true, empty_stream) ) { - #ifdef EZC_HAS_SPECIAL_STREAM - var.str += stream_temp_define.Str(); - #else - var.str += stream_temp_define.str(); - #endif - + CopyStreamToString(stream_temp_define, var.str); var.res = last_res; } else @@ -1890,7 +2687,15 @@ template void Generator::MakeTextEzc(Item & item) { if( item.function.name == L"frame" ) + { MakeEzcFrame(item); + } + else + if( item.function.name == L"clear_all_white_nodes" || item.function.name == L"trim_text_nodes" ) + { + // text nodes are already cleared/trimmed by PatternParser + MakeTextContainer(item); + } // in the future we can use more builtin functions } @@ -1961,20 +2766,24 @@ void Generator::MakeText(Item & item) if( LimitAchieved() ) return; - current_item += 1; - stack_index += 1; - is_generating_for = false; - is_generating_if = false; - is_generating_normal = false; - is_generating_filter = false; + current_item += 1; + stack_index += 1; + is_generating_for = false; + is_generating_if = false; + is_generating_if_def = false; + is_generating_if_not_def = false; + is_generating_normal = false; + is_generating_filter = false; stack_tab[stack_index-1].Clear(); stack_tab[stack_index-1].item = &item; if ( item.type == Item::item_text ) MakeItemText(item); else if( item.type == Item::item_container ) MakeTextContainer(item); - else if( item.type == Item::item_function ) MakeTextNormal(item); + else if( item.type == Item::item_function ) MakeTextFunction(item); else if( item.type == Item::item_if ) MakeTextIf(item); + else if( item.type == Item::item_if_def ) MakeTextIfDef(item); + else if( item.type == Item::item_if_not_def ) MakeTextIfNotDef(item); else if( item.type == Item::item_def ) MakeTextDefine(item); else if( item.type == Item::item_def_if_not_set ) MakeTextDefineIfNotSet(item); else if( item.type == Item::item_let ) MakeTextLet(item); diff --git a/src/item.h b/src/item.h index 90f2d82..f69bf05 100644 --- a/src/item.h +++ b/src/item.h @@ -53,7 +53,7 @@ struct Item { enum Type { - item_none, item_container, item_text, item_function, item_if, + item_none, item_container, item_text, item_function, item_if, item_if_def, item_if_not_def, item_for, item_else, item_end, item_err, item_include, item_comment, item_def, item_def_if_not_set, item_let, item_let_if_not_set, item_filter, item_ezc, item_block, item_return @@ -64,6 +64,7 @@ struct Item { bool is_function; // if true then we have a function parameter, if false then we have a string parameter std::wstring name; // a function or parameter name + std::vector fields; // any number of additional fields after a dot e.g. [name.field1.field2] std::wstring postfix; // a function can have an additional postfix in its name // e.g. [my_function:my_postfix] std::vector parameters; // if is_function is true then it is a function and can have 'parameters' @@ -123,6 +124,7 @@ struct Item for(size_t i=0 ; i + */ + +/* + * Copyright (c) 2021, Tomasz Sowa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name Tomasz Sowa nor the names of contributors to this + * project may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "models.h" + + +#ifdef EZC_HAS_MORM_LIBRARY + + + +namespace Ezc +{ + + +Models::Models() +{ +} + + +Models::~Models() +{ + Clear(); +} + + +void Models::Clear() +{ + models_map.clear(); +} + + + +void Models::Add(const std::wstring & name, morm::Model & model) +{ + morm::Wrapper wrapper; + wrapper.model = &model; + models_map[name] = wrapper; +} + + +void Models::Add(const std::wstring & name, morm::Model * model) +{ + morm::Wrapper wrapper; + wrapper.model = model; + models_map[name] = wrapper; +} + + +void Models::Add(const std::wstring & name, pt::Space & space) +{ + morm::Wrapper wrapper; + wrapper.space_wrapper = new morm::SpaceWrapper(&space); + models_map[name] = wrapper; +} + + +void Models::Add(const std::wstring & name, pt::Space * space) +{ + morm::Wrapper wrapper; + wrapper.space_wrapper = new morm::SpaceWrapper(space); + models_map[name] = wrapper; +} + + +void Models::Add(const std::wstring & name, pt::Date & date) +{ + morm::Wrapper wrapper; + wrapper.date = &date; + models_map[name] = wrapper; +} + + +void Models::Add(const std::wstring & name, pt::Date * date) +{ + morm::Wrapper wrapper; + wrapper.date = date; + models_map[name] = wrapper; +} + + +morm::Wrapper * Models::Find(const std::wstring & name) +{ + auto iterator = models_map.find(name); + + if( iterator != models_map.end() ) + { + return &iterator->second; + } + + return nullptr; +} + + + +} + + +#endif + diff --git a/src/models.h b/src/models.h new file mode 100644 index 0000000..0ae2078 --- /dev/null +++ b/src/models.h @@ -0,0 +1,148 @@ +/* + * This file is a part of EZC -- Easy templating in C++ library + * and is distributed under the BSD 3-Clause licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2021, Tomasz Sowa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name Tomasz Sowa nor the names of contributors to this + * project may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef headerfile_ezc_models +#define headerfile_ezc_models + +#ifdef EZC_HAS_MORM_LIBRARY + +#include "wrapper.h" +#include "funinfo.h" +#include "space/space.h" + + +namespace Ezc +{ + + +class Models +{ +public: + + Models(); + ~Models(); + + void Add(const std::wstring & name, morm::Model & model); + void Add(const std::wstring & name, morm::Model * model); + + void Add(const std::wstring & name, pt::Space & space); + void Add(const std::wstring & name, pt::Space * space); + + void Add(const std::wstring & name, pt::Date & space); + void Add(const std::wstring & name, pt::Date * space); + + template + void Add(const std::wstring & name, std::vector & container) + { + morm::Wrapper wrapper; + wrapper.model_container_wrapper = new morm::ModelWrapperVector(&container); + models_map[name] = wrapper; + } + + template + void Add(const std::wstring & name, std::vector * container) + { + morm::Wrapper wrapper; + wrapper.model_container_wrapper = new morm::ModelWrapperVector(container); + models_map[name] = wrapper; + } + + template + void Add(const std::wstring & name, std::vector & container) + { + morm::Wrapper wrapper; + wrapper.model_container_wrapper = new morm::ModelWrapperVectorPointer(&container); + models_map[name] = wrapper; + } + + template + void Add(const std::wstring & name, std::vector * container) + { + morm::Wrapper wrapper; + wrapper.model_container_wrapper = new morm::ModelWrapperVectorPointer(container); + models_map[name] = wrapper; + } + + template + void Add(const std::wstring & name, std::list & container) + { + morm::Wrapper wrapper; + wrapper.model_container_wrapper = new morm::ModelWrapperList(&container); + models_map[name] = wrapper; + } + + template + void Add(const std::wstring & name, std::list * container) + { + morm::Wrapper wrapper; + wrapper.model_container_wrapper = new morm::ModelWrapperList(container); + models_map[name] = wrapper; + } + + template + void Add(const std::wstring & name, std::list & container) + { + morm::Wrapper wrapper; + wrapper.model_container_wrapper = new morm::ModelWrapperListPointer(&container); + models_map[name] = wrapper; + } + + template + void Add(const std::wstring & name, std::list * container) + { + morm::Wrapper wrapper; + wrapper.model_container_wrapper = new morm::ModelWrapperListPointer(container); + models_map[name] = wrapper; + } + + morm::Wrapper * Find(const std::wstring & name); + void Clear(); + + +protected: + + std::map models_map; + + +}; + +} + +#endif + +#endif + diff --git a/src/outstreams.h b/src/outstreams.h index 5727044..df5840b 100644 --- a/src/outstreams.h +++ b/src/outstreams.h @@ -150,8 +150,8 @@ void OutStreams::ClearMap() { StreamType & str = *(i->second); - #ifdef EZC_HAS_SPECIAL_STREAM - str.Clear(); + #ifdef EZC_GENERATOR_HAS_PT_STREAM + str.clear(); #else str.str(L""); #endif diff --git a/src/patternparser.cpp b/src/patternparser.cpp index cab0b0d..0ac1478 100644 --- a/src/patternparser.cpp +++ b/src/patternparser.cpp @@ -124,37 +124,6 @@ void PatternParser::SetBlocks(Blocks & blocks) } -void PatternParser::SetCommentary(const char * com_start, const char * com_stop) -{ - pt::utf8_to_wide(com_start, commentary_start); - pt::utf8_to_wide(com_stop, commentary_stop); -} - - - -void PatternParser::SetCommentary(const std::string & com_start, const std::string & com_stop) -{ - pt::utf8_to_wide(com_start, commentary_start); - pt::utf8_to_wide(com_stop, commentary_stop); -} - - - -void PatternParser::SetCommentary(const wchar_t * com_start, const wchar_t * com_stop) -{ - commentary_start = com_start; - commentary_stop = com_stop; -} - - - -void PatternParser::SetCommentary(const std::wstring & com_start, const std::wstring & com_stop) -{ - commentary_start = com_start; - commentary_stop = com_stop; -} - - void PatternParser::SetProgramMode(bool program_mode) { this->program_mode = program_mode; @@ -167,19 +136,26 @@ void PatternParser::SetLogger(pt::Log * log) } -void PatternParser::CreateMsg(std::wstring & out, const wchar_t * type, const wchar_t * arg) +void PatternParser::InitializeEnvTab() { - out = commentary_start; - out += L"Ezc: "; - out += type; + env_tab.clear(); - if( arg ) + Env env; + env.clear_all_white_nodes = delete_white_text_items; + env_tab.push_back(env); +} + + +void PatternParser::IncreaseEnvTab() +{ + if( env_tab.empty() ) { - out += ' '; - out += arg; + InitializeEnvTab(); + } + else + { + env_tab.push_back(env_tab.back()); } - - out += commentary_stop; } @@ -195,10 +171,13 @@ void PatternParser::ParseFile(const std::string & file_name, Pattern & pattern) void PatternParser::ParseFile(const char * file_name, Pattern & pattern) { pat = &pattern; + pat->Clear(); pt::utf8_to_wide(file_name, pat->item_root.file_name); include_level = 0; + InitializeEnvTab(); CreateTreeReadIncludeSkipAllowFlag(pat->item_root); + env_tab.clear(); } @@ -215,9 +194,13 @@ void PatternParser::ParseFile(const std::wstring & file_name, Pattern & pattern) void PatternParser::ParseFile(const wchar_t * file_name, Pattern & pattern) { pat = &pattern; + pat->Clear(); pat->item_root.file_name = file_name; include_level = 0; + InitializeEnvTab(); + CreateTreeReadIncludeSkipAllowFlag(pat->item_root); + env_tab.clear(); } @@ -242,11 +225,13 @@ void PatternParser::ParseString(const std::string & str, Pattern & pattern) void PatternParser::ParseString(const wchar_t * str, Pattern & pattern) { pat = &pattern; + pat->Clear(); itext = str; include_level = 0; + InitializeEnvTab(); - pat->item_root.Clear(); CreateTreeContainer(pat->item_root); + env_tab.clear(); } @@ -350,15 +335,25 @@ void PatternParser::ReadFile(const wchar_t * name, std::wstring & result) { if( !IsFileCorrect(name) ) { - CreateMsg(result, L"incorrect file name: ", name); + if( log ) + { + (*log) << pt::Log::log2 << "Ezc: incorrect file name: " << name << pt::Log::logend; + } } else { result.clear(); if( !ReadFileFromDir(directory, name, result) ) + { if( !ReadFileFromDir(directory2, name, result) ) - CreateMsg(result, L"can't open: ", name); + { + if( log ) + { + (*log) << pt::Log::log2 << "Ezc: can't open file: " << name << pt::Log::logend; + } + } + } } } @@ -425,13 +420,7 @@ return *(itext++); bool PatternParser::IsWhite(wchar_t c) { - // 13 (\r) is from a dos file at the end of a line (\r\n) - // 160 is a non-breaking space - - if( c==' ' || c=='\t' || c==13 || c==160 || c==10 ) - return true; - -return false; + return pt::is_white(c, true, true); } @@ -463,7 +452,7 @@ size_t count = 1; void PatternParser::CheckWhiteAndDelete(std::wstring & s) { size_t i; - + if( s.empty() ) return; @@ -486,7 +475,7 @@ bool PatternParser::IsNameChar(wchar_t c) return ((c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || - c=='_' || c=='-' || c=='.' || c=='#' || c=='?'); + c=='_' || c=='-' || c=='#' || c=='?'); } @@ -622,7 +611,28 @@ return res; } +void PatternParser::ReadFunctionFields(Item::Function & function) +{ + std::wstring field; + bool read_next_field = true; + while( *itext == '.' && read_next_field ) + { + itext += 1; + read_next_field = ReadName(field); + + if( read_next_field ) + { + function.fields.emplace_back(field); + } + } + + if( *itext == ':' ) + { + itext += 1; + ReadName(function.postfix); // we allow the postfix to be empty + } +} bool PatternParser::ReadFunction(Item::Function & function, bool with_params) @@ -654,14 +664,12 @@ bool PatternParser::ReadFunction(Item::Function & function, bool with_params) if( res ) { - if( *itext == ':' ) - { - itext += 1; - ReadName(function.postfix); // we allow the postfix to be empty - } + ReadFunctionFields(function); if( with_params ) + { res = ReadParams(function); + } } } @@ -737,6 +745,35 @@ void PatternParser::ReadDirectiveIf(Item & item) } +void PatternParser::ReadDirectiveIfDef(Item & item) +{ + item.type = Item::item_if_def; + + if( ReadFunction(item) ) + { + if( !item.function.is_function || item.function.parameters.size() > 0 ) + { + item.type = Item::item_err; + item.function.Clear(); + } + } +} + + +void PatternParser::ReadDirectiveIfNotDef(Item & item) +{ + item.type = Item::item_if_not_def; + + if( ReadFunction(item) ) + { + if( !item.function.is_function || item.function.parameters.size() > 0 ) + { + item.type = Item::item_err; + item.function.Clear(); + } + } +} + void PatternParser::ReadDirectiveEnd(Item & item) { @@ -870,6 +907,9 @@ void PatternParser::ReadDirectiveFilter(Item & item) } + + + void PatternParser::ReadDirectiveEzc(Item & item) { item.type = Item::item_ezc; @@ -920,7 +960,53 @@ void PatternParser::ReadDirectiveReturn(Item & item) } +/* + * returns true if an Env struct has been added to env_tab + */ +bool PatternParser::CheckEnv(Item & item) +{ + if( item.function.name == L"clear_all_white_nodes" ) + { + IncreaseEnvTab(); + env_tab.back().clear_all_white_nodes = CheckEnvIsYesParameter(item); + return true; + } + if( item.function.name == L"trim_text_nodes" ) + { + IncreaseEnvTab(); + env_tab.back().trim_text_nodes = CheckEnvIsYesParameter(item); + return true; + } + + return false; +} + + +/* + * + * if no parameters are present then we assume the "yes" is by default + * + */ +bool PatternParser::CheckEnvIsYesParameter(Item & item) +{ + if( item.function.parameters.size() > 0 && !item.function.parameters[0]->is_function ) + { + std::wstring & name = item.function.parameters[0]->name; + + if( name == L"yes" || name == L"true" ) + { + return true; + } + else + if( name == L"no" || name == L"false" ) + { + return false; + } + } + + return true; +} void PatternParser::CreateTreeReadItemDirective(Item & item) @@ -934,6 +1020,8 @@ std::wstring name; ReadName(name); if ( name == L"if" ) ReadDirectiveIf(item); + else if( name == L"if-def" ) ReadDirectiveIfDef(item); + else if( name == L"if-not-def" )ReadDirectiveIfNotDef(item); else if( name == L"end" ) ReadDirectiveEnd(item); else if( name == L"else" ) ReadDirectiveElse(item); else if( name == L"for" ) ReadDirectiveFor(item); @@ -966,8 +1054,20 @@ int c; while( (c = ReadCharInText()) != -1 ) item.text += static_cast(c); - if( delete_white_text_items ) - CheckWhiteAndDelete(item.text); + if( !env_tab.empty() ) + { + Env & env = env_tab.back(); + + if( env.clear_all_white_nodes ) + { + CheckWhiteAndDelete(item.text); + } + + if( env.trim_text_nodes ) + { + pt::trim_white(item.text, true, true); + } + } item.type = Item::item_text; } @@ -1142,7 +1242,7 @@ void PatternParser::CreateTreeReadIncludeSkipAllowFlag(Item & item) { if( log ) { - (*log) << pt::Log::log1 << "Ezc: \"include\" directive has reached the maximum level" << pt::Log::logend; + (*log) << pt::Log::log2 << "Ezc: \"include\" directive has reached the maximum level" << pt::Log::logend; } return; @@ -1218,7 +1318,7 @@ void PatternParser::CreateTreeReadBlock(Item & item) -void PatternParser::CreateTreeReadFor(Item & item) +void PatternParser::CreateTreeReadOneChild(Item & item) { Item * pitem = item.AddItem(); @@ -1247,22 +1347,29 @@ bool PatternParser::CreateTree(Item & item) } while( item.type == Item::item_comment || item.type == Item::item_block ); + bool reduce_env_tab = false; + + if(item.type == Item::item_ezc) + reduce_env_tab = CheckEnv(item); + // such container can be read in program mode if( item.type == Item::item_container ) CreateTreeContainer(item); - if( item.type == Item::item_if ) - CreateTreeReadIf(item); + if( item.type == Item::item_if || item.type == Item::item_if_def || item.type == Item::item_if_not_def ) + CreateTreeReadIf(item); // reads one child or two if [else] statement is present - // CHECK ME is it correct to check item_filter and item_ezc here and call CreateTreeReadFor? if( item.type == Item::item_for || item.type == Item::item_filter || item.type == Item::item_ezc ) - CreateTreeReadFor(item); + CreateTreeReadOneChild(item); if( item.type == Item::item_include ) CreateTreeReadInclude(item); + if( reduce_env_tab && !env_tab.empty() ) + env_tab.resize(env_tab.size() - 1); + return true; } diff --git a/src/patternparser.h b/src/patternparser.h index 037d357..3e755cc 100644 --- a/src/patternparser.h +++ b/src/patternparser.h @@ -79,20 +79,27 @@ public: void AllowInclude(bool allow); void DeleteWhiteTextItems(bool del); void SetIncludeMax(int include_max); - void SetBlocks(Blocks & blocks); - - void SetCommentary(const char * com_start, const char * com_stop); - void SetCommentary(const std::string & com_start, const std::string & com_stop); - void SetCommentary(const wchar_t * com_start, const wchar_t * com_stop); - void SetCommentary(const std::wstring & com_start, const std::wstring & com_stop); - void SetProgramMode(bool program_mode); - void SetLogger(pt::Log * log); private: + struct Env + { + bool clear_all_white_nodes; + bool trim_text_nodes; + + Env() + { + clear_all_white_nodes = false; + trim_text_nodes = false; + } + + }; + + std::vector env_tab; + // the output object Pattern * pat; @@ -117,8 +124,6 @@ private: std::wstring directory, directory2; - std::wstring commentary_start, commentary_stop; - int include_level, include_level_max; @@ -140,7 +145,8 @@ private: pt::Log * log; - void CreateMsg(std::wstring & out, const wchar_t * type, const wchar_t * arg = 0); + void InitializeEnvTab(); + void IncreaseEnvTab(); void ReadFile(const std::wstring & name, std::wstring & result); void ReadFile(const wchar_t * name, std::wstring & result); @@ -165,10 +171,13 @@ private: bool ReadString(std::wstring & str); bool ReadParamString(Item::Function & function); bool ReadParams(Item::Function & function); + void ReadFunctionFields(Item::Function & function); bool ReadFunction(Item::Function & function, bool with_params); bool ReadFunction(Item & item); void ReadDirectiveIf(Item & item); + void ReadDirectiveIfDef(Item & item); + void ReadDirectiveIfNotDef(Item & item); void ReadDirectiveEnd(Item & item); void ReadDirectiveElse(Item & item); void ReadDirectiveFor(Item & item); @@ -185,6 +194,9 @@ private: void ReadDirectiveReturn(Item & item); void ReadNormalStatement(Item & item); + bool CheckEnv(Item & item); + bool CheckEnvIsYesParameter(Item & item); + void CreateTreeReadDirectiveExpression(Item & item, bool is_statement); bool CreateTreeCheckProgramDirective(Item & item); bool CreateTreeReadExpression(Item & item); @@ -195,7 +207,7 @@ private: bool CreateTreeReadItem(Item & item); void CreateTreeReadIf(Item & item); void CreateTreeReadBlock(Item & item); - void CreateTreeReadFor(Item & item); + void CreateTreeReadOneChild(Item & item); bool CreateTree(Item & item); void CreateTreeContainer(Item & item); void CreateTreeReadInclude(Item & item);