From 079a62c2303deeb5238e1254c67e233b7843ec82 Mon Sep 17 00:00:00 2001 From: Tomasz Sowa Date: Mon, 9 Dec 2024 16:36:53 +0100 Subject: [PATCH] WIP: add a Val struct as an input/output when calling a function --- src/env.h | 78 ++-- src/generator.h | 769 +++++++++++++++++++---------------- src/val.cpp | 1012 +++++++++++++++++++++++++++++++++++++++++++++++ src/val.h | 252 ++++++++++++ 4 files changed, 1744 insertions(+), 367 deletions(-) create mode 100644 src/val.cpp create mode 100644 src/val.h diff --git a/src/env.h b/src/env.h index ca8c555..3346758 100644 --- a/src/env.h +++ b/src/env.h @@ -39,6 +39,7 @@ #include #include #include "item.h" +#include "val.h" #include "textstream/stream.h" @@ -49,27 +50,27 @@ namespace Ezc /* a variable */ -struct Var -{ - /* - * if true then means 'str' is a function name and should be called (res is ignored) - * - * if false then means 'str' is a string value and res is a boolean value - */ - bool is_function; +// struct Var +// { +// /* +// * if true then means 'str' is a function name and should be called (res is ignored) +// * +// * if false then means 'str' is a string value and res is a boolean value +// */ +// bool is_function; - std::wstring str; // a string value - bool res; // a boolean value +// std::wstring str; // a string value +// bool res; // a boolean value - Var() - { - res = false; - is_function = false; - } -}; +// Var() +// { +// res = false; +// is_function = false; +// } +// }; -typedef std::map Vars; +//typedef std::map Vars; @@ -141,25 +142,36 @@ struct Stack }; -// !! IMPROVE ME -// the name is bad -// may it should be called Env (environment) or FunEnv + struct Env { - // a result consists of a string and a boolean value - // output stream - pt::Stream & 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; + + // output + Val & res; + + // + // old interface but still available + // + + // a result consists of a string and a boolean value + // output stream + pt::Stream & out; // OLD INTERFACE a reference to res.stream + // return value from a user's function (default false if not set directly by the function) + //bool res; + + // old interface DEPRECATED // the first parameter // you can always use it even if there are not any parameters (params is empty) // in such a way the reference points to an empty string - const std::wstring & par; + //const std::wstring & par; + + + // + // an input stream used in [filter] statement // if there is other statement than [filter] then this is an empty stream @@ -208,11 +220,11 @@ struct Env // arguments: output_stream, table_of_parameters, the_first_parameter Env(pt::Stream & o, - std::vector & pars, - const std::wstring & first_par, - const pt::Stream & input_stream, - Stack & s, - const Item & item_) : out(o), params(pars), par(first_par), in(input_stream), stack(s), item(item_) + std::vector & pars, + Val & res, + const pt::Stream & input_stream, + Stack & s, + const Item & item_) : out(o), params(pars), res(res), in(input_stream), stack(s), item(item_) { Clear(); } diff --git a/src/generator.h b/src/generator.h index e2c5ab6..197f982 100644 --- a/src/generator.h +++ b/src/generator.h @@ -54,6 +54,7 @@ #ifdef EZC_HAS_MORM_LIBRARY #include "model.h" +#include "valwrapper.h" #endif namespace Ezc @@ -78,7 +79,7 @@ public: void SetBlocks(Blocks & blocks); void SetFunctions(Functions & functions); void SetObjects(Objects & objects); - void SetVariables(Vars & variables); // [def] and [let] + void SetVariables(Vals & variables); // [def] and [let] void SetLogger(pt::Log & logger); @@ -149,40 +150,69 @@ private: struct FindHelper { - std::wstring * fun_name; + FindHelper( + Item::Function & item_fun, + const std::wstring & fun_name, + std::vector & fields, + Val & current, + std::vector & parameters, + Val & result, + pt::Stream & out_stream, + const pt::Stream & in_stream) : + item_fun(item_fun), fun_name(fun_name), fields(fields), current(current), parameters(parameters), result(result), out_stream(out_stream), in_stream(in_stream) + { + #ifdef EZC_HAS_MORM_LIBRARY + field_index = 0; + #endif - BaseObj * base_obj; - int method_index; - typename Functions::UserFunction * function; - Item * item_block; - Var * variable; + } + + FindHelper(const FindHelper &) = delete; + + Item::Function & item_fun; + const std::wstring & fun_name; + std::vector & fields; + Val & current; + std::vector & parameters; + Val & result; + pt::Stream & out_stream; + const pt::Stream & in_stream; + + + //std::wstring * fun_name; + + //BaseObj * base_obj; + //int method_index; + //typename Functions::UserFunction * function; + //Item * item_block; + //Val * variable; #ifdef EZC_HAS_MORM_LIBRARY - morm::Wrapper * wrapper; + //morm::Wrapper * wrapper; size_t field_index; #endif - FindHelper() - { - fun_name = nullptr; + // FindHelper() + // { + //fun_name = nullptr; - base_obj = nullptr; - method_index = -1; - function = nullptr; - item_block = nullptr; - variable = nullptr; + //base_obj = nullptr; + //method_index = -1; + //function = nullptr; + //item_block = nullptr; + //variable = nullptr; #ifdef EZC_HAS_MORM_LIBRARY - wrapper = nullptr; - field_index = 0; + //wrapper = nullptr; + //field_index = 0; #endif - } + //} }; struct BlockStack { - std::vector args; + std::vector args; pt::Stream * out_stream; bool was_return; }; @@ -203,7 +233,7 @@ private: #ifdef EZC_HAS_MORM_LIBRARY Models * pmodels; #endif - Vars * pvars; + Vals * pvals; pt::Log * plog; @@ -241,7 +271,7 @@ private: pt::Stream * stream_temp1, * stream_temp_define; // last result from a user function (FunInfo::res) - bool last_res; + //bool last_res; // true if this Generator is working now bool is_generator_working; @@ -301,7 +331,7 @@ private: bool IsTestingFunctionExistence(); - bool CheckBlockArgument(int arg_index, FindHelper & find_helper); + bool CheckBlockArgument(FindHelper & find_helper); bool FindInCache(Item::Function & item_fun, FindHelper & find_helper); @@ -309,69 +339,67 @@ private: 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 FindInFunctionsAndBlocks(FindHelper & find_helper); + bool FindInVariables(FindHelper & find_helper); + bool Find(FindHelper & find_helper); - void PrepareEnvStruct(Env & info); + void PrepareEnvStruct(Env & env); - void CallFunction(typename Functions::UserFunction & function, Env & info); + void CallFunction(typename Functions::UserFunction & function, Env & env); + void CallFunction(FindHelper & find_helper); - void CallFunction(typename Functions::UserFunction & function, - std::vector & parameters, - pt::Stream & out_stream, - const pt::Stream & in_stream); - - bool CallBlock(Item & item_block, - std::vector & parameters, - pt::Stream & out_stream); + bool CallBlock(FindHelper & find_helper); void CallObject(BaseObj & base_obj, int method_index, Env & info); - void PrintDate(pt::Date * date, std::vector & parameters, pt::Stream & out_stream); - bool PrintDatePart(pt::Date * date, const std::wstring & field, std::vector & parameters, pt::Stream & out_stream); + void PrintDate(pt::Date * date, std::vector & parameters, pt::Stream & out_stream); + bool PrintDatePart(pt::Date * date, const std::wstring & field, std::vector & parameters, pt::Stream & out_stream); - bool CallDate(FindHelper & find_helper, std::vector & fields, std::vector & parameters, pt::Stream & out_stream); + bool CallDate(Val & current, std::vector & fields, std::vector & parameters, pt::Stream & out_stream); - void PrintLastSpaceField(pt::Space * space, std::vector & parameters, pt::Stream & out_stream); - void CallSpaceObjectForLastField(std::vector & parameters, pt::Stream & out_stream, pt::Space * space); + void PrintLastSpaceField(pt::Space * space, std::vector & parameters, pt::Stream & out_stream); + void CallSpaceObjectForLastField(std::vector & parameters, pt::Stream & 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, pt::Stream & out_stream, + void CallSpaceTableForLastField(morm::SpaceWrapper & space_wrapper, std::vector & parameters, pt::Stream & 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, pt::Stream & out_stream); + bool CallSpace(FindHelper & find_helper, std::vector & fields, std::vector & parameters, Val & result, pt::Stream & out_stream); #ifdef EZC_HAS_MORM_LIBRARY - bool CallModelField(morm::Model & model, const std::wstring & field, std::vector & parameters, pt::Stream & out_stream, const pt::Stream & in_stream); - bool CallModel(morm::Model & model, FindHelper & find_helper, std::vector & fields, std::vector & parameters, pt::Stream & out_stream, const pt::Stream & in_stream); - void FindLastModelWrapper(FindHelper & find_helper, std::vector & fields); - bool CallWrapper(FindHelper & find_helper, std::vector & fields, std::vector & parameters, pt::Stream & out_stream, const pt::Stream & in_stream); + bool CallModelField(FindHelper & find_helper, morm::Model & model); + bool CallModel(FindHelper & find_helper, morm::Model & model); + void FindLastModelWrapper(FindHelper & find_helper); + bool CallWrapper(FindHelper & find_helper); #endif void CallObject(BaseObj & base_obj, int method_index, - std::vector & parameters, + std::vector & parameters, + Val & result, pt::Stream & out_stream, const pt::Stream & in_stream); bool CallVariable(Item::Function & item_fun, - Var & variable, - std::vector & parameters, + Val & variable, + std::vector & parameters, + Val & result, pt::Stream & out_stream, const pt::Stream & in_stream); + bool PrepareParameters(FindHelper & find_helper); + bool ReduceFields(FindHelper & find_helper); + bool CallValue(FindHelper & find_helper); + void CleanupParameters(std::vector & parameters); + bool Call(Item::Function & item_fun, std::wstring * fun_name, - pt::Stream & out_stream, - bool clear_out_stream, + Val & result, pt::Stream & out_stream, const pt::Stream & in_stream); - bool Call(Item::Function & item_fun); - wchar_t CreateSpecialChar(wchar_t c); const wchar_t * PrintSpecialChar(const wchar_t * start, const wchar_t * end); void PrintSpecialText(const wchar_t * start, const wchar_t * end); @@ -381,13 +409,13 @@ 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 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); - void DumpSpaceIfNeeded(std::vector & parameters, pt::Stream & out_stream, pt::Space * space); - void DumpModelIfNeeded(morm::Model & model, std::vector & parameters, pt::Stream & out_stream); + void DumpSpaceIfNeeded(std::vector & parameters, pt::Stream & out_stream, pt::Space * space); + void DumpModelIfNeeded(morm::Model & model, std::vector & parameters, pt::Stream & out_stream); pt::Stream * FindAddOutputStream(const std::wstring & name); void CopyTmpStreamToOutputStreams(Item::Function & fun, pt::Stream & ezc_out_tmp_stream); @@ -419,10 +447,10 @@ private: void MakeItemText(Item & item); void MakeTextContainer(Item & item); void MakeTextFunction(Item & item); - void MakeTextDefine(Item & item, Var & var); + void MakeTextDefine(Item & item, Val & val); void MakeTextDefine(Item & item); void MakeTextDefineIfNotSet(Item & item); - void MakeTextLet(Item & item, Var & var); + void MakeTextLet(Item & item, Val & val); void MakeTextLet(Item & item); void MakeTextLetIfNotSet(Item & item); void MakeTextFilter(Item & item); @@ -450,7 +478,7 @@ Generator::Generator() : empty_stream() pblocks = nullptr; pfunctions = nullptr; pobjects = nullptr; - pvars = nullptr; + pvals = nullptr; plog = nullptr; #ifdef EZC_HAS_MORM_LIBRARY @@ -493,7 +521,7 @@ Generator::operator=(const Generator & n) pblocks = n.pblocks; pfunctions = n.pfunctions; pobjects = n.pobjects; - pvars = n.pvars; + pvals = n.pvals; plog = n.plog; #ifdef EZC_HAS_MORM_LIBRARY @@ -579,9 +607,9 @@ void Generator::SetObjects(Objects & objects) -void Generator::SetVariables(Vars & variables) +void Generator::SetVariables(Vals & variables) { - pvars = &variables; + pvals = &variables; } @@ -1030,9 +1058,9 @@ bool Generator::IsTestingFunctionExistence() -bool Generator::CheckBlockArgument(int arg_index, FindHelper & find_helper) +bool Generator::CheckBlockArgument(FindHelper & find_helper) { - if( arg_index < 0 ) + if( find_helper.item_fun.arg < 0 ) return false; // it's a numeric function -- an argument to a block e.g.: [1] @@ -1040,9 +1068,9 @@ bool Generator::CheckBlockArgument(int arg_index, FindHelper & find_helper) { BlockStack & block_stack = block_stack_tab[block_stack_index-1]; - if( size_t(arg_index) < block_stack.args.size() ) + if( size_t(find_helper.item_fun.arg) < block_stack.args.size() ) { - find_helper.variable = &block_stack.args[arg_index]; + find_helper.current.set(block_stack.args[find_helper.item_fun.arg]); return true; } } @@ -1087,55 +1115,80 @@ return false; bool Generator::FindInModels(FindHelper & find_helper) { + bool found = false; + if( pmodels ) { - morm::Wrapper * m = pmodels->Find(*find_helper.fun_name); + // morm::Wrapper probably will be removed.... + morm::Wrapper * m = pmodels->Find(find_helper.fun_name); if( m ) { - find_helper.wrapper = m; - return true; + if( m->model ) + { + find_helper.current.set(*m->model); + found = true; + } + else + if( m->model_container_wrapper ) + { + find_helper.current.set(*m->model_container_wrapper); + found = true; + } + else + if( m->date ) + { + find_helper.current.set(*m->date); + found = true; + } + else + if( m->space_wrapper ) + { + find_helper.current.set(*m->space_wrapper); + found = true; + } } } - return false; + return found; } #endif - -bool Generator::FindInFunctionsAndBlocks(const std::wstring & name, FindHelper & find_helper) +// IMPROVEME split me into two functions +bool Generator::FindInFunctionsAndBlocks(FindHelper & find_helper) { - if( pobjects ) - { - typename Objects::Iterator i = pobjects->Find(name, find_helper.method_index); + // Objects will be removed in the future + // if( pobjects ) + // { + // typename Objects::Iterator i = pobjects->Find(name, find_helper.method_index); - if( i != pobjects->End() ) - { - find_helper.base_obj = *i; - return true; - } - } + // if( i != pobjects->End() ) + // { + // find_helper.base_obj = *i; + // return true; + // } + // } if( pfunctions ) { - typename Functions::Iterator i = pfunctions->Find(name); + typename Functions::Iterator i = pfunctions->Find(find_helper.fun_name); if( i != pfunctions->End() ) { - find_helper.function = &i->second; + find_helper.current.set(i->second); return true; } } if( pblocks ) { - Blocks::Iterator i = pblocks->Find(name); + Blocks::Iterator i = pblocks->Find(find_helper.fun_name); if( i != pblocks->End() ) { - find_helper.item_block = &i->second; + find_helper.current.set(i->second); return true; } } @@ -1145,15 +1198,15 @@ return false; -bool Generator::FindInVariables(const std::wstring & name, FindHelper & find_helper) +bool Generator::FindInVariables(FindHelper & find_helper) { - if( pvars ) + if( pvals ) { - Vars::iterator i = pvars->find(name); + Vals::iterator i = pvals->find(find_helper.fun_name); - if( i != pvars->end() ) + if( i != pvals->end() ) { - find_helper.variable = &(i->second); + find_helper.current.set(i->second); return true; } } @@ -1168,110 +1221,94 @@ bool Generator::FindInVariables(const std::wstring & name, FindHelper & find_hel * and if not null then means: as a funcion name we are not using item_fun.name but fun_name */ -bool Generator::Find(Item::Function & item_fun, FindHelper & find_helper) +// give me a better name, FindWhat.... +//bool Generator::Find(Item::Function & item_fun, FindHelper & find_helper) +bool Generator::Find(FindHelper & find_helper) { - if( CheckBlockArgument(item_fun.arg, find_helper) ) + if( CheckBlockArgument(find_helper) ) return true; #ifdef EZC_HAS_MORM_LIBRARY if( FindInModels(find_helper) ) return true; - if( !item_fun.fields.empty() && !IsTestingFunctionExistence() ) + if( !find_helper.item_fun.fields.empty() && !IsTestingFunctionExistence() ) { - CreateMsg(L"unknown model", find_helper.fun_name->c_str()); + CreateMsg(L"unknown model", find_helper.fun_name.c_str()); return false; } #endif - if( FindInCache(item_fun, find_helper) ) + // Cache will be removed in the future + // if( FindInCache(item_fun, find_helper) ) + // return true; + + if( FindInFunctionsAndBlocks(find_helper) ) return true; - if( FindInFunctionsAndBlocks(*find_helper.fun_name, find_helper) ) - return true; - - if( FindInVariables(*find_helper.fun_name, find_helper) ) + if( FindInVariables(find_helper) ) return true; if( !IsTestingFunctionExistence() ) - CreateMsg(L"unknown function", find_helper.fun_name->c_str()); + CreateMsg(L"unknown function", find_helper.fun_name.c_str()); return false; } -void Generator::PrepareEnvStruct(Env & info) +void Generator::PrepareEnvStruct(Env & env) { - info.Clear(); + env.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; + env.is_for = is_generating_for; + env.is_if = is_generating_if; + env.is_if_def = is_generating_if_def; + env.is_if_not_def = is_generating_if_not_def; + env.is_normal = is_generating_normal; + env.is_filter = is_generating_filter; + env.iter = env.stack.iter; + env.stack_tab = stack_tab.data(); + env.stack_index = stack_index-1; } -void Generator::CallFunction(typename Functions::UserFunction & function, Env & info) +void Generator::CallFunction(typename Functions::UserFunction & function, Env & env) { - PrepareEnvStruct(info); - (function)(info); - last_res = info.res; + PrepareEnvStruct(env); + (function)(env); + //last_res = env.res; } - - -void Generator::CallFunction(typename Functions::UserFunction & function, - std::vector & parameters, - pt::Stream & out_stream, - const pt::Stream & in_stream) +void Generator::CallFunction(FindHelper & find_helper) { if( !IsTestingFunctionExistence() ) { - if( parameters.empty() ) - { - Env info(out_stream, parameters, empty, in_stream, stack_tab[stack_index-1], *stack_tab[stack_index-1].item); - CallFunction(function, info); - } - else - { - Env info(out_stream, parameters, parameters[0].str, in_stream, stack_tab[stack_index-1], *stack_tab[stack_index-1].item); - CallFunction(function, info); - } + Env env(find_helper.out_stream, find_helper.parameters, find_helper.result, find_helper.in_stream, stack_tab[stack_index-1], *stack_tab[stack_index-1].item); + CallFunction(find_helper.current.user_function, env); } } - - - void Generator::CallObject(BaseObj & base_obj, int method_index, Env & info) { PrepareEnvStruct(info); base_obj.CallFun(method_index, info); - last_res = info.res; + //last_res = info.res; } - - - -bool Generator::HasParam(std::vector & parameters, const wchar_t * param1, const wchar_t * param2) +bool Generator::HasParam(std::vector & parameters, const wchar_t * param1, const wchar_t * param2) { - for(Var & var : parameters) + for(Val & val : parameters) { - if( !var.is_function ) + if( !val.is_function ) { - if( var.str == param1 || (param2 && var.str == param2) ) + if( val.str == param1 || (param2 && val.str == param2) ) { return true; } @@ -1282,23 +1319,19 @@ bool Generator::HasParam(std::vector & parameters, const wchar_t * param1, } - - -bool Generator::ShouldMakeSpaceDump(std::vector & parameters) +bool Generator::ShouldMakeSpaceDump(std::vector & parameters) { return HasParam(parameters, L"dump", L"dump_to_space"); } - -bool Generator::ShouldMakeJsonDump(std::vector & parameters) +bool Generator::ShouldMakeJsonDump(std::vector & parameters) { return HasParam(parameters, L"dump_to_json"); } - -bool Generator::IsPrettyPrint(std::vector & parameters) +bool Generator::IsPrettyPrint(std::vector & parameters) { return HasParam(parameters, L"pretty"); } @@ -1306,7 +1339,7 @@ bool Generator::IsPrettyPrint(std::vector & parameters) -void Generator::DumpSpaceIfNeeded(std::vector & parameters, pt::Stream & out_stream, pt::Space * space) +void Generator::DumpSpaceIfNeeded(std::vector & parameters, pt::Stream & out_stream, pt::Space * space) { bool dump_space = ShouldMakeSpaceDump(parameters); bool dump_json = ShouldMakeJsonDump(parameters); @@ -1329,7 +1362,7 @@ void Generator::DumpSpaceIfNeeded(std::vector & parameters, pt::Stream & ou -void Generator::DumpModelIfNeeded(morm::Model & model, std::vector & parameters, pt::Stream & out_stream) +void Generator::DumpModelIfNeeded(morm::Model & model, std::vector & parameters, pt::Stream & out_stream) { bool dump_space = ShouldMakeSpaceDump(parameters); bool dump_json = ShouldMakeJsonDump(parameters); @@ -1358,7 +1391,7 @@ void Generator::DumpModelIfNeeded(morm::Model & model, std::vector & parame -void Generator::PrintDate(pt::Date * date, std::vector & parameters, pt::Stream & out_stream) +void Generator::PrintDate(pt::Date * date, std::vector & parameters, pt::Stream & out_stream) { bool is_roman = HasParam(parameters, L"roman"); bool is_no_sec = HasParam(parameters, L"no_sec"); @@ -1385,7 +1418,7 @@ void Generator::PrintDate(pt::Date * date, std::vector & parameters, pt::St -bool Generator::PrintDatePart(pt::Date * date, const std::wstring & field, std::vector & parameters, pt::Stream & out_stream) +bool Generator::PrintDatePart(pt::Date * date, const std::wstring & field, std::vector & parameters, pt::Stream & out_stream) { bool is_test = IsTestingFunctionExistence(); @@ -1441,7 +1474,7 @@ bool Generator::PrintDatePart(pt::Date * date, const std::wstring & field, std:: -bool Generator::CallDate(FindHelper & find_helper, std::vector & fields, std::vector & parameters, pt::Stream & out_stream) +bool Generator::CallDate(Val & current, std::vector & fields, std::vector & parameters, pt::Stream & out_stream) { bool found = true; bool all_fields_known = (find_helper.field_index == fields.size()); @@ -1449,12 +1482,12 @@ bool Generator::CallDate(FindHelper & find_helper, std::vector & f if( all_fields_known ) { - PrintDate(find_helper.wrapper->date, parameters, out_stream); + PrintDate(current.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( !PrintDatePart(current.date, fields[find_helper.field_index], parameters, out_stream) ) { if( !IsTestingFunctionExistence() ) { @@ -1481,7 +1514,7 @@ bool Generator::CallDate(FindHelper & find_helper, std::vector & f -void Generator::CallSpaceObjectForLastField(std::vector & parameters, pt::Stream & out_stream, pt::Space * space) +void Generator::CallSpaceObjectForLastField(std::vector & parameters, pt::Stream & out_stream, pt::Space * space) { if( IsTestingFunctionExistence() ) { @@ -1513,7 +1546,7 @@ pt::Space * Generator::CallSpaceObjectForMiddleField(std::wstring & root_space_n void Generator::CallSpaceTableForLastField( - morm::SpaceWrapper & space_wrapper, std::vector & parameters, pt::Stream & out_stream, pt::Space * space, size_t model_wrapper_space_table_index) + morm::SpaceWrapper & space_wrapper, std::vector & parameters, pt::Stream & out_stream, pt::Space * space, size_t model_wrapper_space_table_index) { pt::Space::TableType * table = space->get_table(); @@ -1580,7 +1613,7 @@ pt::Space * Generator::CallSpaceTableForMiddleField(morm::SpaceWrapper & space_w -void Generator::PrintLastSpaceField(pt::Space * space, std::vector & parameters, pt::Stream & out_stream) +void Generator::PrintLastSpaceField(pt::Space * space, std::vector & parameters, pt::Stream & out_stream) { bool no_escape = HasParam(parameters, L"raw", L"noescape"); @@ -1599,11 +1632,11 @@ void Generator::PrintLastSpaceField(pt::Space * space, std::vector & parame -bool Generator::CallSpace(FindHelper & find_helper, std::vector & fields, std::vector & parameters, pt::Stream & out_stream) +bool Generator::CallSpace(FindHelper & find_helper, std::vector & fields, std::vector & parameters, Val & result, pt::Stream & out_stream) { morm::SpaceWrapper * space_wrapper = find_helper.wrapper->space_wrapper; pt::Space * space = space_wrapper->get_space(); - last_res = false; + //last_res = false; size_t field_index = find_helper.field_index; size_t model_wrapper_space_table_index = 0; @@ -1669,12 +1702,12 @@ bool Generator::CallSpace(FindHelper & find_helper, std::vector & { if( IsTestingFunctionExistence() ) { - last_res = true; + //last_res = true; } else { PrintLastSpaceField(space, parameters, out_stream); - last_res = space->to_bool(); + //last_res = space->to_bool(); } field_index += 1; @@ -1701,9 +1734,10 @@ bool Generator::CallSpace(FindHelper & find_helper, std::vector & #ifdef EZC_HAS_MORM_LIBRARY -bool Generator::CallModelField( - morm::Model & model, const std::wstring & field, std::vector & parameters, pt::Stream & out_stream, const pt::Stream & in_stream) +bool Generator::CallModelField(FindHelper & find_helper, morm::Model & model) { + const std::wstring & field = find_helper.fields[find_helper.field_index]; + /* * 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 @@ -1713,19 +1747,19 @@ bool Generator::CallModelField( pt::WTextStream str; bool found = false; - if( parameters.empty() ) + if( find_helper.parameters.empty() ) { - Env info(out_stream, parameters, empty, in_stream, stack_tab[stack_index-1], *stack_tab[stack_index-1].item); - PrepareEnvStruct(info); - found = model.get_raw_value(nullptr, field.c_str(), nullptr, info, str, false); - last_res = info.res; + Env env(find_helper.out_stream, find_helper.parameters, empty, find_helper.in_stream, stack_tab[stack_index-1], *stack_tab[stack_index-1].item); + PrepareEnvStruct(env); + found = model.get_raw_value(nullptr, field.c_str(), nullptr, env, str, false); + //last_res = env.res; } else { - Env info(out_stream, parameters, parameters[0].str, in_stream, stack_tab[stack_index-1], *stack_tab[stack_index-1].item); - PrepareEnvStruct(info); - found = model.get_raw_value(nullptr, field.c_str(), nullptr, info, str, false); - last_res = info.res; + Env env(find_helper.out_stream, find_helper.parameters, find_helper.parameters[0].str, find_helper.in_stream, stack_tab[stack_index-1], *stack_tab[stack_index-1].item); + PrepareEnvStruct(env); + found = model.get_raw_value(nullptr, field.c_str(), nullptr, env, str, false); + //last_res = env.res; } if( found && !str.empty()) @@ -1739,30 +1773,30 @@ bool Generator::CallModelField( -bool Generator::CallModel(morm::Model & model, FindHelper & find_helper, std::vector & fields, - std::vector & parameters, pt::Stream & out_stream, const pt::Stream & in_stream) +bool Generator::CallModel(FindHelper & find_helper, morm::Model & model) { bool found = true; - if( find_helper.field_index == fields.size() ) + if( find_helper.field_index == find_helper.fields.size() ) { // all fields items are models or models containers // at the moment we do not set last_res // we don't know whether the last object has properties (fields) or not if( !IsTestingFunctionExistence() ) { - DumpModelIfNeeded(model, parameters, out_stream); + DumpModelIfNeeded(model, find_helper.parameters, find_helper.out_stream); } } else - if( find_helper.field_index + 1 == fields.size() ) + if( find_helper.field_index + 1 == find_helper.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( !CallModelField(find_helper, model) ) { 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"); + CreateMsg(L"cannot find ", find_helper.fun_name, find_helper.fields, L", unknown property ", + find_helper.fields[find_helper.field_index].c_str(), L" of a model object"); } found = false; @@ -1772,7 +1806,8 @@ bool Generator::CallModel(morm::Model & model, FindHelper & find_helper, std::ve { 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"); + CreateMsg(L"cannot find ", find_helper.fun_name, find_helper.fields, L", ", find_helper.fields[find_helper.field_index].c_str(), + L" is not a model nor a model container nor a space"); } found = false; @@ -1784,35 +1819,54 @@ bool Generator::CallModel(morm::Model & model, FindHelper & find_helper, std::ve -void Generator::FindLastModelWrapper(FindHelper & find_helper, std::vector & fields) +void Generator::FindLastModelWrapper(FindHelper & find_helper) { - for(find_helper.field_index = 0 ; find_helper.field_index < fields.size() && find_helper.wrapper->has_model_object() ; ++find_helper.field_index) + for(find_helper.field_index = 0 ; find_helper.field_index < find_helper.fields.size() && find_helper.current.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); + std::wstring & field = find_helper.fields[find_helper.field_index]; + Val * child_wrapper = find_helper.current.find_child(field); if( !child_wrapper ) { morm::Model * model = nullptr; - if( find_helper.wrapper->model ) + if( find_helper.current.type == Val::TYPE_MODEL && find_helper.current.model ) { - model = find_helper.wrapper->model; + model = find_helper.current.model; } else - if( find_helper.wrapper->model_container_wrapper ) + if( find_helper.current.type == Val::TYPE_MODEL_CONTAINER_WRAPPER && find_helper.current.model_container_wrapper ) { - model = find_helper.wrapper->model_container_wrapper->get_model(); + model = find_helper.current.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 ) { + // IMPROVEME improve the morm library + // return a Val instead of a Wrapper 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); + //child_wrapper = find_helper.wrapper->add_child(field, new_wrapper); + + Val child; + + if( new_wrapper.model ) + child.set(model); + else + if( new_wrapper.model_container_wrapper ) + child.set(new_wrapper.model_container_wrapper); + else + if( new_wrapper.space_wrapper ) + child.set(new_wrapper.space_wrapper); + else + if( new_wrapper.date ) + child.set(new_wrapper.date); + + if( child.type != Val::TYPE_VOID ) + child_wrapper = find_helper.current.add_child(field, child); } } } @@ -1820,56 +1874,59 @@ void Generator::FindLastModelWrapper(FindHelper & find_helper, std::vector & fields, - std::vector & parameters, pt::Stream & out_stream, const pt::Stream & in_stream) +bool Generator::CallWrapper(FindHelper & find_helper) { bool found = true; - last_res = false; - FindLastModelWrapper(find_helper, fields); + //last_res = false; + + // this should be moved to Reduce() method + // and here should be only a calling + FindLastModelWrapper(find_helper); // 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()); + bool all_fields_known = (find_helper.field_index == find_helper.fields.size()); + bool last_field_not_known = (find_helper.field_index + 1 == find_helper.fields.size()); - if( find_helper.wrapper->space_wrapper ) + if( find_helper.current.space_wrapper ) { - found = CallSpace(find_helper, fields, parameters, out_stream); + found = CallSpace(find_helper); } - if( find_helper.wrapper->date ) + if( find_helper.current.date ) { - found = CallDate(find_helper, fields, parameters, out_stream); + found = CallDate(find_helper); } - if( find_helper.wrapper->model ) + if( find_helper.current.model ) { - found = CallModel(*find_helper.wrapper->model, find_helper, fields, parameters, out_stream, in_stream); + found = CallModel(find_helper, *find_helper.current.model); } - if( find_helper.wrapper->model_container_wrapper ) + if( find_helper.current.model_container_wrapper ) { - morm::Model * model = find_helper.wrapper->model_container_wrapper->get_model(); + morm::Model * model = find_helper.current.model_container_wrapper->get_model(); if( model ) { - found = CallModel(*model, find_helper, fields, parameters, out_stream, in_stream); + found = CallModel(find_helper, *model); } 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?"); + CreateMsg(L"model ", find_helper.fun_name, find_helper.fields, L" is not initialized, have you forgotten to use [for ...] statement?"); found = false; } } @@ -1878,14 +1935,14 @@ bool Generator::CallWrapper(FindHelper & find_helper, std::vector { 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(); + find_helper.current.model_container_wrapper->increment_iterator(); + find_helper.current.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(); + //last_res = !find_helper.wrapper->model_container_wrapper->is_container_empty(); } } } @@ -1899,32 +1956,23 @@ bool Generator::CallWrapper(FindHelper & find_helper, std::vector void Generator::CallObject(BaseObj & base_obj, - int method_index, - std::vector & parameters, - pt::Stream & out_stream, - const pt::Stream & in_stream) + int method_index, + std::vector & parameters, + Val & result, + pt::Stream & out_stream, + const pt::Stream & in_stream) { if( !IsTestingFunctionExistence() ) { - if( parameters.empty() ) - { - Env 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 - { - Env 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); - } + Env env(out_stream, parameters, result, in_stream, stack_tab[stack_index-1], *stack_tab[stack_index-1].item); + CallObject(base_obj, method_index, env); } } -bool Generator::CallBlock(Item & item_block, - std::vector & parameters, - pt::Stream & out_stream) +bool Generator::CallBlock(FindHelper & find_helper) { if( block_stack_index >= block_stack_tab.size() ) { @@ -1938,15 +1986,15 @@ bool Generator::CallBlock(Item & item_block, BlockStack & block_stack = block_stack_tab[block_stack_index]; block_stack.was_return = false; - block_stack.args = parameters; + block_stack.args = find_helper.parameters; output_stream = block_stack.out_stream; ClearStream(*output_stream); block_stack_index += 1; - MakeText(item_block); + MakeText(*find_helper.current.item_block); - CopyStream(*output_stream, out_stream); + //CopyStream(*output_stream, find_helper.out_stream); // last_res is set by [return ...] statement or other last evaluated function ClearStream(*output_stream); @@ -1954,17 +2002,17 @@ bool Generator::CallBlock(Item & item_block, block_stack_index -= 1; } -return true; + return true; } -bool Generator::CallVariable(Item::Function & item_fun, Var & variable, std::vector & parameters, pt::Stream & out_stream, const pt::Stream & in_stream) +bool Generator::CallVariable(Item::Function & item_fun, Var & variable, std::vector & parameters, Val & result, pt::Stream & out_stream, const pt::Stream & in_stream) { if( variable.is_function ) { - return Call(item_fun, &variable.str, out_stream, false, in_stream); + return Call(item_fun, &variable.str, result, out_stream, in_stream); } else { @@ -1979,6 +2027,84 @@ bool Generator::CallVariable(Item::Function & item_fun, Var & variable, std::vec } +bool Generator::PrepareParameters(FindHelper & find_helper) +{ + find_helper.parameters.resize(find_helper.item_fun.parameters.size()); + + for(size_t i=0 ; i < find_helper.item_fun.parameters.size() ; ++i) + { + // IMPROVEME use a pooler of streams? + find_helper.parameters[i].set_output_stream(main_stream->new_empty()); + Item::Function & fun_child = *find_helper.item_fun.parameters[i]; + + if( fun_child.is_function ) + { + Call(fun_child, nullptr, find_helper.parameters[i], *find_helper.parameters[i].output_stream, *empty_stream); + + //CopyStreamToString(*local_temp_stream, parameters[i].str); + //parameters[i].res = last_res; + } + else + { + // parameters[i].str = fun_child.name; + // parameters[i].res = ConvertToBool(fun_child.name); + find_helper.parameters[i] << fun_child.name; + } + } +} + + +// give me a better name +bool Generator::ReduceFields(FindHelper & find_helper) +{ + + +} + + +bool Generator::CallValue(FindHelper & find_helper) +{ +#ifdef EZC_HAS_MORM_LIBRARY + if( find_helper.current.type == Val::TYPE_MODEL && find_helper.current.model ) + return CallWrapper(find_helper); + else + if( find_helper.current.type == Val::TYPE_MODEL_CONTAINER_WRAPPER && find_helper.current.model_container_wrapper ) + return CallWrapper(find_helper); + else + if( find_helper.current.type == Val::TYPE_DATE && find_helper.current.date ) + return CallWrapper(find_helper); + else + if( find_helper.current.type == Val::TYPE_SPACE_WRAPPER && find_helper.current.space_wrapper ) + return CallWrapper(find_helper); + else +#endif + // if( find_helper.base_obj ) // OBJECTS WILL BE REMOVED + // CallObject(*find_helper.base_obj, find_helper.method_index, parameters, result, out_stream, in_stream); + //else + if( find_helper.current.type == Val::TYPE_FUNCTION && find_helper.current.user_function ) + CallFunction(find_helper); + else + if( find_helper.current.type == Val::TYPE_ITEM_BLOCK && find_helper.current.item_block ) + return CallBlock(find_helper); // result? + + // else + // if( find_helper.variable ) + // return CallVariable(item_fun, *find_helper.variable, parameters, result, out_stream, in_stream); + +} + + +void Generator::CleanupParameters(std::vector & parameters) +{ + for(Val & val : parameters) + { + delete val.output_stream; + val.output_stream = nullptr; + } +} + + + /* * 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 @@ -1987,86 +2113,50 @@ bool Generator::CallVariable(Item::Function & item_fun, Var & variable, std::vec */ bool Generator::Call(Item::Function & item_fun, - std::wstring * fun_name, - pt::Stream & out_stream, - bool clear_out_stream, - const pt::Stream & in_stream) + std::wstring * fun_name, + Val & result, + pt::Stream & out_stream, + const pt::Stream & in_stream) { -FindHelper find_helper; -std::vector parameters; + Val current; + std::vector parameters; - if( clear_out_stream ) - ClearStream(out_stream); + if( !fun_name ) + fun_name = &item_fun.name; + + FindHelper find_helper(item_fun, *fun_name, item_fun.fields, current, parameters, result, out_stream, in_stream); + + + // if( clear_out_stream ) + // ClearStream(out_stream); // if constexpr(is_autoescape_stream) // out_stream.Escape(true); - out_stream.escape_input(true); + //out_stream.escape_input(true); - find_helper.fun_name = fun_name; - if( !find_helper.fun_name ) - find_helper.fun_name = &item_fun.name; - - if( !Find(item_fun, find_helper) ) + if( !Find(find_helper) ) return false; - parameters.resize(item_fun.parameters.size()); + PrepareParameters(find_helper); + ReduceFields(find_helper); + bool status = false; - for(size_t i=0 ; i local_temp_stream(main_stream->new_empty()); - Call(fun_child, nullptr, *local_temp_stream, true, *empty_stream); - - CopyStreamToString(*local_temp_stream, parameters[i].str); - parameters[i].res = last_res; - } - else - { - parameters[i].str = fun_child.name; - parameters[i].res = ConvertToBool(fun_child.name); - } + status = CallValue(find_helper); + } + catch(...) + { + // rethrow or just generate a log? } -#ifdef EZC_HAS_MORM_LIBRARY - if( find_helper.wrapper ) - return CallWrapper(find_helper, item_fun.fields, parameters, out_stream, in_stream); - else -#endif - if( find_helper.base_obj ) - CallObject(*find_helper.base_obj, find_helper.method_index, parameters, out_stream, in_stream); - else - if( find_helper.function ) - CallFunction(*find_helper.function, parameters, out_stream, in_stream); - else - 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; -} - - - -// return: true if a function or variable was found and called - -bool Generator::Call(Item::Function & item_fun) -{ - bool status = Call(item_fun, nullptr, *stream_temp1, true, *empty_stream); - ClearStream(*stream_temp1); + CleanupParameters(parameters); return status; } - - wchar_t Generator::CreateSpecialChar(wchar_t c) { wchar_t res = 0; @@ -2512,12 +2602,18 @@ void Generator::MakeTextFunction(Item & item) { if( output_stream && is_output_stream_allowed ) { - Call(item.function, nullptr, *output_stream, false, *empty_stream); + Val result(output_stream); + + // does we need both seperate: result and output_stream? + if( Call(item.function, nullptr, result, *output_stream, *empty_stream) ) + { + result.serialize_to(*output_stream); + } } else { - Call(item.function, nullptr, *stream_temp1, false, *empty_stream); - ClearStream(*stream_temp1); + Val result(stream_temp1); + Call(item.function, nullptr, result, *stream_temp1, *empty_stream); } } } @@ -2545,19 +2641,24 @@ void Generator::MakeTextIf_go(Item & item, bool result) void Generator::MakeTextIf(Item & item) { + Val result(stream_temp1); is_generating_if = true; if( program_mode ) { + // is it ok now? EvaluateProgramNode(item); } else { - if( !Call(item.function) ) + bool status = Call(item.function, nullptr, result, *stream_temp1, *empty_stream); + ClearStream(*stream_temp1); + + if( !status ) return; } - MakeTextIf_go(item, last_res); + MakeTextIf_go(item, result.to_bool()); } @@ -2637,10 +2738,10 @@ void Generator::MakeTextFor(Item & item) -void Generator::MakeTextDefine(Item & item, Var & var) +void Generator::MakeTextDefine(Item & item, Val & val) { - var.str.clear(); - var.res = ConvertToBool(var.str); + val.str.clear(); + val.res = ConvertToBool(val.str); var.is_function = false; if( item.function.parameters.empty() ) @@ -2661,8 +2762,8 @@ void Generator::MakeTextDefine(Item & item, Var & var) // call function if( Call(fun, nullptr, *stream_temp_define, true, *empty_stream) ) { - CopyStreamToString(*stream_temp_define, var.str); - var.res = last_res; + CopyStreamToString(*stream_temp_define, val.str); + val.res = last_res; } else { @@ -2671,8 +2772,8 @@ void Generator::MakeTextDefine(Item & item, Var & var) } else { - var.str = fun.name; - var.res = ConvertToBool(fun.name); + val.str = fun.name; + val.res = ConvertToBool(fun.name); } } @@ -2680,32 +2781,32 @@ void Generator::MakeTextDefine(Item & item, Var & var) void Generator::MakeTextDefine(Item & item) { - if( !can_use_vars || !pvars ) + if( !can_use_vars || !pvals ) { CreateMsg(L"[def] statement not available"); return; } - Var & var = (*pvars)[item.function.name]; - MakeTextDefine(item, var); + Val & val = (*pvals)[item.function.name]; + MakeTextDefine(item, val); } void Generator::MakeTextDefineIfNotSet(Item & item) { - if( !can_use_vars || !pvars ) + if( !can_use_vars || !pvals ) { CreateMsg(L"[def?] statement not available"); return; } - Vars::iterator vi = pvars->find(item.function.name); + Vals::iterator vi = pvals->find(item.function.name); - if( vi == pvars->end() ) + if( vi == pvals->end() ) { - Var & var = (*pvars)[item.function.name]; - MakeTextDefine(item, var); + Val & val = (*pvals)[item.function.name]; + MakeTextDefine(item, val); } } @@ -2713,10 +2814,10 @@ void Generator::MakeTextDefineIfNotSet(Item & item) -void Generator::MakeTextLet(Item & item, Var & var) +void Generator::MakeTextLet(Item & item, Val & val) { - var.str.clear(); - var.res = ConvertToBool(var.str); + val.str.clear(); + val.res = ConvertToBool(val.str); var.is_function = true; if( item.function.parameters.empty() ) @@ -2732,12 +2833,12 @@ void Generator::MakeTextLet(Item & item, Var & var) } Item::Function & fun = *item.function.parameters[0]; - var.str = fun.name; + val.str = fun.name; var.is_function = fun.is_function; if( !fun.is_function ) { - var.res = ConvertToBool(var.str); + val.res = ConvertToBool(val.str); } } @@ -2745,32 +2846,32 @@ void Generator::MakeTextLet(Item & item, Var & var) void Generator::MakeTextLet(Item & item) { - if( !can_use_vars || !pvars ) + if( !can_use_vars || !pvals ) { CreateMsg(L"[let] statement not available"); return; } - Var & var = (*pvars)[item.function.name]; - MakeTextLet(item, var); + Val & val = (*pvals)[item.function.name]; + MakeTextLet(item, val); } void Generator::MakeTextLetIfNotSet(Item & item) { - if( !can_use_vars || !pvars ) + if( !can_use_vars || !pvals ) { CreateMsg(L"[let?] statement not available"); return; } - Vars::iterator vi = pvars->find(item.function.name); + Vals::iterator vi = pvals->find(item.function.name); - if( vi == pvars->end() ) + if( vi == pvals->end() ) { - Var & var = (*pvars)[item.function.name]; - MakeTextLet(item, var); + Val & val = (*pvals)[item.function.name]; + MakeTextLet(item, val); } } diff --git a/src/val.cpp b/src/val.cpp new file mode 100644 index 0000000..9d20216 --- /dev/null +++ b/src/val.cpp @@ -0,0 +1,1012 @@ +/* + * This file is a part of EZC -- Easy templating in C++ library + * and is distributed under the 2-Clause BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2024, 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: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. 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. + * + * 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 HOLDER 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 "val.h" + +#ifdef EZC_HAS_MORM_LIBRARY +#include "model.h" +#endif + + +namespace Ezc +{ + + +Val::Val() +{ + output_stream = nullptr; + output_stream_original_size = 0; + initialize_empty(); +} + + +Val::Val(pt::Stream * output_stream) +{ + this->output_stream = output_stream; + this->output_stream_original_size = output_stream->size(); + initialize_empty(); +} + + +Val::Val(const Val & val) +{ + initialize_empty(); + copy(val); +} + + +Val & Val::operator=(const Val & val) +{ + clear(); + copy(val); + return *this; +} + + +void Val::copy(const Val & val) +{ + type = val.type; + user_function = val.user_function; + model = val.model; + model_container_wrapper = val.model_container_wrapper; + date = val.date; + space_wrapper = val.space_wrapper; + space_local = val.space_local; + stream = val.stream; + space = val.space; + output_stream = val.output_stream; + output_stream_original_size = val.output_stream_original_size; + + if( model_container_wrapper ) + { + model_container_wrapper->increment_reference_counter(); + } + + if( space_wrapper ) + { + space_wrapper->increment_reference_counter(); + } + + // childs_map don't need to be copied +} + + +Val::~Val() +{ + clear(); +} + + +// output_stream can be a nullpointer +void Val::set_output_stream(pt::Stream * output_stream) +{ + this->output_stream = output_stream; + this->output_stream_original_size = (output_stream) ? output_stream->size() : 0; +} + + +void Val::set_output_stream(pt::Stream & output_stream) +{ + set_output_stream(&output_stream); +} + + +void Val::initialize_empty() +{ + type = TYPE_VOID; + user_function = nullptr; + model = nullptr; + model_container_wrapper = nullptr; + date = nullptr; + space_wrapper = nullptr; + space = nullptr; + stream = nullptr; + item_block = nullptr; +} + + +void Val::clear() +{ + if( model_container_wrapper ) + { + model_container_wrapper->decrement_reference_counter(); + + if( model_container_wrapper->get_reference_counter() == 0 && model_container_wrapper->should_be_auto_removed() ) + { + delete model_container_wrapper; + } + } + + if( space_wrapper ) + { + space_wrapper->decrement_reference_counter(); + + if( space_wrapper->get_reference_counter() == 0 && space_wrapper->should_be_auto_removed() ) + { + delete space_wrapper; + } + } + + initialize_empty(); + space_local.clear(); + clear_childs(); +} + + +void Val::clear_childs() +{ + childs_map.clear(); +} + + +Val * Val::add_child(const std::wstring & child_name, const Val & val) +{ + Val & v = childs_map[child_name]; + v.clear(); + v = val; + return &v; +} + + +Val * Val::find_child(const std::wstring & child_name) +{ + auto i = childs_map.find(child_name); + + if( i != childs_map.end() ) + { + return &i->second; + } + + return nullptr; +} + + +bool Val::has_object() +{ + return type != TYPE_VOID; +} + + +bool Val::has_model_object() +{ + return model || model_container_wrapper; +} + + +bool Val::to_bool() const +{ + switch(type) + { + case TYPE_VOID: + return false; + + case TYPE_SPACE_LOCAL: + return space_local.to_bool(); + + case TYPE_STREAM: + return !stream->empty(); + + case TYPE_FUNCTION: + case TYPE_DATE: // date can be evaluated to true if it's different than the Unix epoch + case TYPE_MODEL: + case TYPE_ITEM_BLOCK: + break; + + case TYPE_SPACE_WRAPPER: + return space_wrapper->get_space()->to_bool(); + + case TYPE_SPACE: + return space->to_bool(); + + case TYPE_MODEL_CONTAINER_WRAPPER: + return !model_container_wrapper->is_container_empty(); + + case TYPE_OUTPUT_STREAM: + return output_stream->size() != output_stream_original_size; + } + + return false; +} + + +void Val::set(const char * str) +{ + clear(); + type = TYPE_SPACE_LOCAL; + space_local.set(str); +} + + +void Val::set(const wchar_t * str) +{ + clear(); + type = TYPE_SPACE_LOCAL; + space_local.set(str); +} + + +void Val::set(const std::string & str) +{ + clear(); + type = TYPE_SPACE_LOCAL; + space_local.set(str); +} + + +void Val::set(const std::wstring & str) +{ + clear(); + type = TYPE_SPACE_LOCAL; + space_local.set(str); +} + + +void Val::set(bool val) +{ + clear(); + type = TYPE_SPACE_LOCAL; + space_local.set(val); +} + + +void Val::set(short val) +{ + clear(); + type = TYPE_SPACE_LOCAL; + space_local.set(val); +} + + +void Val::set(int val) +{ + clear(); + type = TYPE_SPACE_LOCAL; + space_local.set(val); +} + + +void Val::set(long val) +{ + clear(); + type = TYPE_SPACE_LOCAL; + space_local.set(val); +} + + +void Val::set(long long val) +{ + clear(); + type = TYPE_SPACE_LOCAL; + space_local.set(val); +} + + +void Val::set(unsigned short val) +{ + clear(); + type = TYPE_SPACE_LOCAL; + space_local.set(val); +} + + +void Val::set(unsigned int val) +{ + clear(); + type = TYPE_SPACE_LOCAL; + space_local.set(val); +} + + +void Val::set(unsigned long val) +{ + clear(); + type = TYPE_SPACE_LOCAL; + space_local.set(val); +} + + +void Val::set(unsigned long long val) +{ + clear(); + type = TYPE_SPACE_LOCAL; + space_local.set(val); +} + + +void Val::set(float val) +{ + clear(); + type = TYPE_SPACE_LOCAL; + space_local.set(val); +} + + +void Val::set(double val) +{ + clear(); + type = TYPE_SPACE_LOCAL; + space_local.set(val); +} + + +void Val::set(long double val) +{ + clear(); + type = TYPE_SPACE_LOCAL; + space_local.set(val); +} + + +void Val::set(pt::Stream & str) +{ + clear(); + type = TYPE_STREAM; + this->stream = &str; +} + + +void Val::set(UserFunction user_function) +{ + clear(); + type = TYPE_FUNCTION; + this->user_function = user_function; +} + + +void Val::set(pt::Date & date) +{ + clear(); + type = TYPE_DATE; + this->date = &date; +} + + +void Val::set(morm::Model & model) +{ + clear(); + type = TYPE_MODEL; + this->model = &model; +} + + +void Val::set(morm::ModelContainerWrapper & model_container_wrapper) +{ + clear(); + type = TYPE_MODEL_CONTAINER_WRAPPER; + this->model_container_wrapper = &model_container_wrapper; + this->model_container_wrapper->increment_reference_counter(); +} + + +template +void Val::set(std::vector & model_container) +{ + clear(); + type = TYPE_MODEL_CONTAINER_WRAPPER; + this->model_container_wrapper = new morm::ModelWrapperVector(&model_container); +} + + +template +void Val::set(std::list & model_container) +{ + clear(); + type = TYPE_MODEL_CONTAINER_WRAPPER; + this->model_container_wrapper = new morm::ModelWrapperList(&model_container); +} + + +template +void Val::set(std::vector & model_container) +{ + clear(); + type = TYPE_MODEL_CONTAINER_WRAPPER; + this->model_container_wrapper = new morm::ModelWrapperVectorPointer(&model_container); +} + + +template +void Val::set(std::list & model_container) +{ + clear(); + type = TYPE_MODEL_CONTAINER_WRAPPER; + this->model_container_wrapper = new morm::ModelWrapperListPointer(&model_container); +} + + +void Val::set(morm::SpaceWrapper & space_wrapper) +{ + clear(); + type = TYPE_SPACE_WRAPPER; + this->space_wrapper = &space_wrapper; + this->space_wrapper->increment_reference_counter(); +} + + +void Val::set(pt::Space & space, bool create_wrapper) +{ + clear(); + + if( create_wrapper ) + { + type = TYPE_SPACE_WRAPPER; + this->space_wrapper = new morm::SpaceWrapper(&space); + } + else + { + type = TYPE_SPACE; + this->space = &space; + } +} + + +void Val::set(Val & val) +{ + clear(); + + switch(val.type) + { + case TYPE_VOID: + break; + + case TYPE_SPACE_LOCAL: + space_local = val.space_local; + break; + + case TYPE_STREAM: + stream = val.stream; + break; + + case TYPE_FUNCTION: + user_function = val.user_function; + break; + + case TYPE_DATE: + date = val.date; + break; + + case TYPE_MODEL: + model = val.model; + break; + + case TYPE_SPACE_WRAPPER: + space_wrapper = val.space_wrapper; + break; + + case TYPE_SPACE: + space = val.space; + break; + + case TYPE_MODEL_CONTAINER_WRAPPER: + model_container_wrapper = val.model_container_wrapper; + break; + + case TYPE_OUTPUT_STREAM: + output_stream = val.output_stream; + break; + + case TYPE_ITEM_BLOCK: + item_block = val.item_block; + break; + } +} + + +void Val::set(Item & item_block) +{ + clear(); + type = TYPE_ITEM_BLOCK; + this->item_block = &item_block; +} + + + +// bool Val::is_equal(const char * str) const +// { +// switch(type) +// { +// case TYPE_SPACE_LOCAL: +// if( space_local.is_str() || space_local.is_wstr() ) +// return is_equal_string(str); + +// if( space_local.is_bool() ) +// return is_equal_bool(str); + +// // IMPLEMENTME +// // implement the rest of conversion methods + +// return false; + +// case TYPE_VOID: +// case TYPE_STREAM: +// case TYPE_FUNCTION: +// case TYPE_DATE: +// case TYPE_MODEL: +// case TYPE_MODEL_CONTAINER_WRAPPER: +// case TYPE_SPACE_WRAPPER: +// case TYPE_SPACE: +// // IMPLEMENTME +// break; + +// } + +// return false; +// } + + + +// bool Val::is_equal(const wchar_t * str) const +// { +// switch(type) +// { +// case TYPE_SPACE_LOCAL: +// if( space_local.is_str() || space_local.is_wstr() ) +// return is_equal_string(str); + +// if( space_local.is_bool() ) +// return is_equal_bool(str); + +// // IMPLEMENTME +// // implement the rest of conversion methods + +// return false; + +// case TYPE_VOID: +// case TYPE_STREAM: +// case TYPE_FUNCTION: +// case TYPE_DATE: +// case TYPE_MODEL: +// case TYPE_MODEL_CONTAINER_WRAPPER: +// case TYPE_SPACE_WRAPPER: +// case TYPE_SPACE: +// // IMPLEMENTME +// break; + +// } + +// return false; +// } + + + +// bool Val::is_equal(const std::string & str) const +// { +// return is_equal(str.c_str()); +// } + + + +// bool Val::is_equal(const std::wstring & str) const +// { +// return is_equal(str.c_str()); +// } + + + +// bool Val::is_equal_bool(const char * str) const +// { +// if( space_local.to_bool() ) +// { +// return str[0] != 0; +// } +// else +// { +// return str[0] == 0; +// } +// } + + + +// bool Val::is_equal_string(const char * str) const +// { +// if( space_local.is_str() ) +// { +// return space_local.is_equal(str); +// } +// else +// if( space_local.is_wstr() ) +// { +// std::string space_str_utf8; +// pt::wide_to_utf8(*space_local.get_wstr(), space_str_utf8); +// return space_str_utf8 == str; +// } + +// return false; +// } + + + + +// bool Val::is_equal_bool(const wchar_t * str) const +// { +// if( space_local.to_bool() ) +// { +// return str[0] != 0; +// } +// else +// { +// return str[0] == 0; +// } +// } + + + +// bool Val::is_equal_string(const wchar_t * str) const +// { +// if( space_local.is_wstr() ) +// { +// return space_local.is_equal(str); +// } +// else +// if( space_local.is_str() ) +// { +// std::string str_utf8; +// pt::wide_to_utf8(str, str_utf8); +// return space_local.is_equal(str_utf8); +// } + +// return false; +// } + + + +void Val::serialize_to(pt::Stream & str) +{ + str.escape_input(true); + morm::Model * m; + + switch(type) + { + case TYPE_SPACE_LOCAL: + space_local.serialize_to_string(str); + break; + + case TYPE_STREAM: + str << stream; // operator(void*) will be taken? !!!! + break; + + case TYPE_DATE: + date->SerializeISO(str); + break; + + case TYPE_MODEL: + model->to_text(str); + break; + + case TYPE_MODEL_CONTAINER_WRAPPER: + m = model_container_wrapper->get_model(); + + if( m ) + m->to_text(str); + + break; + + case TYPE_SPACE_WRAPPER: + space_wrapper->get_space()->serialize_to_string(str); + break; + + case TYPE_SPACE: + space->serialize_to_string(str); + break; + + case TYPE_VOID: + case TYPE_FUNCTION: + case TYPE_OUTPUT_STREAM: + case TYPE_ITEM_BLOCK: + break; + } +} + + +void Val::assert_type_output_stream() +{ + if( type != Val::TYPE_OUTPUT_STREAM ) + { + clear(); + type = TYPE_OUTPUT_STREAM; + } +} + + +Val & Val::operator<<(const char * str) +{ + assert_type_output_stream(); + + if( output_stream ) + { + *output_stream << str; + } + + return *this; +} + + +Val & Val::operator<<(const wchar_t * str) +{ + assert_type_output_stream(); + + if( output_stream ) + { + *output_stream << str; + } + + return *this; +} + + +Val & Val::operator<<(const std::string & str) +{ + assert_type_output_stream(); + + if( output_stream ) + { + *output_stream << str; + } + + return *this; +} + + +Val & Val::operator<<(const std::wstring & str) +{ + assert_type_output_stream(); + + if( output_stream ) + { + *output_stream << str; + } + + return *this; +} + + +Val & Val::operator<<(char val) +{ + assert_type_output_stream(); + + if( output_stream ) + { + *output_stream << val; + } + + return *this; +} + + +Val & Val::operator<<(unsigned char val) +{ + assert_type_output_stream(); + + if( output_stream ) + { + *output_stream << val; + } + + return *this; +} + + +Val & Val::operator<<(wchar_t val) +{ + assert_type_output_stream(); + + if( output_stream ) + { + *output_stream << val; + } + + return *this; +} + + +Val & Val::operator<<(bool val) +{ + assert_type_output_stream(); + + if( output_stream ) + { + *output_stream << val; + } + + return *this; +} + + +Val & Val::operator<<(short val) +{ + assert_type_output_stream(); + + if( output_stream ) + { + *output_stream << val; + } + + return *this; +} + + +Val & Val::operator<<(int val) +{ + assert_type_output_stream(); + + if( output_stream ) + { + *output_stream << val; + } + + return *this; +} + + +Val & Val::operator<<(long val) +{ + assert_type_output_stream(); + + if( output_stream ) + { + *output_stream << val; + } + + return *this; +} + + +Val & Val::operator<<(long long val) +{ + assert_type_output_stream(); + + if( output_stream ) + { + *output_stream << val; + } + + return *this; +} + + +Val & Val::operator<<(unsigned short val) +{ + assert_type_output_stream(); + + if( output_stream ) + { + *output_stream << val; + } + + return *this; +} + + +Val & Val::operator<<(unsigned int val) +{ + assert_type_output_stream(); + + if( output_stream ) + { + *output_stream << val; + } + + return *this; +} + + +Val & Val::operator<<(unsigned long val) +{ + assert_type_output_stream(); + + if( output_stream ) + { + *output_stream << val; + } + + return *this; +} + + +Val & Val::operator<<(unsigned long long val) +{ + assert_type_output_stream(); + + if( output_stream ) + { + *output_stream << val; + } + + return *this; +} + + +Val & Val::operator<<(float val) +{ + assert_type_output_stream(); + + if( output_stream ) + { + *output_stream << val; + } + + return *this; +} + + +Val & Val::operator<<(double val) +{ + assert_type_output_stream(); + + if( output_stream ) + { + *output_stream << val; + } + + return *this; +} + + +Val & Val::operator<<(long double val) +{ + assert_type_output_stream(); + + if( output_stream ) + { + *output_stream << val; + } + + return *this; +} + + +Val & Val::operator<<(const pt::Stream & str) +{ + assert_type_output_stream(); + + if( output_stream ) + { + *output_stream << str; + } + + return *this; +} + + +Val & Val::operator=(bool res) +{ + set(res); + return *this; +} + + + +} // namespace Ezc + + diff --git a/src/val.h b/src/val.h new file mode 100644 index 0000000..6ed4bf7 --- /dev/null +++ b/src/val.h @@ -0,0 +1,252 @@ +/* + * This file is a part of EZC -- Easy templating in C++ library + * and is distributed under the 2-Clause BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2024, 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: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. 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. + * + * 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 HOLDER 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_val +#define headerfile_ezc_val + +#include "spacewrapper.h" +#include "date/date.h" +#include "item.h" +#include "modelcontainerwrapper.h" +#include "textstream/textstream.h" + + +namespace morm +{ +class Model; +} + + + + +namespace Ezc +{ + + +struct Env; + + +/* + +*/ +class Val +{ +public: + + typedef void (*UserFunction)(Env &); + + enum Type + { + TYPE_VOID, + TYPE_SPACE_LOCAL, + TYPE_STREAM, + TYPE_FUNCTION, + TYPE_DATE, + TYPE_MODEL, + TYPE_MODEL_CONTAINER_WRAPPER, + TYPE_SPACE_WRAPPER, + TYPE_SPACE, + TYPE_OUTPUT_STREAM, + TYPE_ITEM_BLOCK, + }; + + + Val(); + Val(pt::Stream * output_stream); + Val(const Val & val); + Val & operator=(const Val & val); + ~Val(); + // IMPROVEME add move cctor and operator= + + void set_output_stream(pt::Stream * output_stream); + void set_output_stream(pt::Stream & output_stream); + + Val * add_child(const std::wstring & child_name, const Val & val); + Val * find_child(const std::wstring & child_name); + + bool has_object(); + bool has_model_object(); + + void clear(); + void clear_childs(); + + + bool to_bool() const; + + + void set(const char * str); + void set(const wchar_t * str); + void set(const std::string & str); + void set(const std::wstring & str); + + void set(bool val); + void set(short val); + void set(int val); + void set(long val); + void set(long long val); + void set(unsigned short val); + void set(unsigned int val); + void set(unsigned long val); + void set(unsigned long long val); + + void set(float val); + void set(double val); + void set(long double val); + + void set(pt::Stream & str); + + void set(UserFunction user_function); + + void set(pt::Date & date); + + void set(morm::Model & model); + + void set(morm::ModelContainerWrapper & model_container_wrapper); + + template + void set(std::vector & model_container); + + template + void set(std::list & model_container); + + template + void set(std::vector & model_container); + + template + void set(std::list & model_container); + + void set(morm::SpaceWrapper & space_wrapper); + void set(pt::Space & space, bool create_wrapper = true); + + void set(Val & val); + void set(Item & item_block); + + // bool is_equal(const char * str) const; + // bool is_equal(const wchar_t * str) const; + + // bool is_equal(const std::string & str) const; + // bool is_equal(const std::wstring & str) const; + + void serialize_to(pt::Stream & str); + + + Val & operator<<(const char * str); + Val & operator<<(const wchar_t * str); + Val & operator<<(const std::string & str); + Val & operator<<(const std::wstring & str); + Val & operator<<(char val); + Val & operator<<(unsigned char val); + Val & operator<<(wchar_t val); + Val & operator<<(bool val); + Val & operator<<(short val); + Val & operator<<(int val); + Val & operator<<(long val); + Val & operator<<(long long val); + Val & operator<<(unsigned short val); + Val & operator<<(unsigned int val); + Val & operator<<(unsigned long val); + Val & operator<<(unsigned long long val); + Val & operator<<(float val); + Val & operator<<(double val); + Val & operator<<(long double val); + Val & operator<<(const pt::Stream & str); + + Val & operator=(bool res); + + + Type type; + pt::Space space_local; + + UserFunction user_function; + + // Wrapper + morm::Model * model; + morm::ModelContainerWrapper * model_container_wrapper; + pt::Date * date; + morm::SpaceWrapper * space_wrapper; + // + + pt::Space * space; + pt::Stream * stream; + + Item * item_block; + + + + // output stream + pt::Stream * output_stream; + size_t output_stream_original_size; + +private: + + + std::map childs_map; + + void initialize_empty(); + void copy(const Val & val); + + // bool is_equal_bool(const char * str) const; + // bool is_equal_string(const char * str) const; + + // bool is_equal_bool(const wchar_t * str) const; + // bool is_equal_string(const wchar_t * str) const; + + void assert_type_output_stream(); + + + /* + * old + */ + + + /* + * if true then means 'str' is a function name and should be called (res is ignored) + * + * if false then means 'str' is a string value and res is a boolean value + */ + //bool is_function; + + //std::wstring str; // a string value + //bool res; // a boolean value + +}; + + +typedef std::map Vals; + + +} // namespace Ezc + +#endif +