added: [return ...] statement for a block

changed: a user definied function now is able to get a string and a boolean value (parameters)
changed: we do not longer support aliases for variables
         a variable is only a string and a boolean value now



git-svn-id: svn://ttmath.org/publicrep/ezc/trunk@981 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
Tomasz Sowa 2014-10-28 17:46:24 +00:00
parent 6bd8889456
commit 0a7bd3159a
5 changed files with 153 additions and 135 deletions

View File

@ -46,6 +46,16 @@
namespace Ezc
{
/*
a variable
*/
struct Var
{
std::wstring str; // a string value
bool res; // a boolean value
};
/*
a base class for your own function data class
@ -111,16 +121,19 @@ struct Stack
// !! IMPROVE ME
// the name is bad
// may it should be called Env (environment)
// may it should be called Env (environment) or FunEnv
template<class StreamType>
struct FunInfo
{
// a result consists of a string and a boolean value
// output stream
StreamType & out;
// return value from a user's function (default false if not set directly by the function)
bool res;
// table of parameters
// the table can be empty
std::vector<std::wstring> & params;
std::vector<Var> & params;
// the first parameter
// you can always use it even if there are not any parameters (params is empty)
@ -158,12 +171,10 @@ struct FunInfo
// for other statements than [for] this is always zero
size_t iter;
// return value from a user's function (default false if not set directly by the function)
bool res;
// arguments: output_stream, table_of_parameters, the_first_parameter
FunInfo(StreamType & o,
std::vector<std::wstring> & pars,
std::vector<Var> & pars,
const std::wstring & first_par,
const StreamType & input_stream,
Stack & s) : out(o), params(pars), par(first_par), in(input_stream), stack(s)

View File

@ -39,7 +39,6 @@
#ifndef headerfile_ezc_generator
#define headerfile_ezc_generator
#include "vars.h"
#include "blocks.h"
#include "pattern.h"
#include "functions.h"
@ -126,10 +125,18 @@ public:
private:
// variables set
typedef std::map<std::wstring, Var> Vars;
Vars vars;
Var temp_var;
struct BlockStack
{
std::vector<std::wstring> args;
std::vector<Var> args;
StreamType * out_stream;
bool was_return;
};
std::vector<BlockStack> block_stack_tab;
@ -150,23 +157,11 @@ private:
Blocks * pblocks;
Functions<StreamType> * pfunctions;
// variables set
Vars vars;
// output_tmp_stream is used when outputting to more than one stream
// (first we output to output_tmp_stream and then the content is copied
// to the correct streams)
StreamType output_tmp_stream;
// local_temp_stream is used when there are nested function calls
// e.g.: [function1 [function2]]
// function2 will be redirected to local_temp_stream and the string
// will be copied to Item::function.par std::wstring object
StreamType local_temp_stream;
std::vector<std::wstring> parameters;
// pointers to the output streams
std::vector<StreamType*> output_stream_tab;
@ -259,8 +254,6 @@ private:
Item ** item_block);
bool FindInVariables(const std::wstring & name,
typename Functions<StreamType>::UserFunction ** function,
Item ** item_block,
std::wstring ** variable);
bool Find(const Item::Function & item_fun,
@ -272,12 +265,12 @@ private:
FunInfo<StreamType> & info);
void CallFunction(typename Functions<StreamType>::UserFunction * function,
std::vector<std::wstring> & params,
StreamType & out_stream,
const StreamType & in_stream);
std::vector<Var> & parameters,
StreamType & out_stream,
const StreamType & in_stream);
bool CallBlock(Item & item_block,
std::vector<std::wstring> & params,
std::vector<Var> & parameters,
StreamType & out_stream);
bool Call(Item::Function & item_fun,
@ -325,6 +318,7 @@ private:
void MakeTextDefine(Item & item);
void MakeTextFilter(Item & item);
void MakeTextEzc(Item & item);
void MakeTextReturn(Item & item);
void MakeText(Item & item);
void MakeEzcStream(Item::Function & fun);
@ -729,7 +723,7 @@ void Generator<StreamType>::Generate()
filter_index = 0;
stack_index = 0;
block_stack_index = 0;
vars.Clear();
vars.clear();
if( ppattern )
{
@ -741,7 +735,8 @@ void Generator<StreamType>::Generate()
if( output_stream_index.size() > 1 )
WriteTmpStreamToStreams();
vars.Clear();
vars.clear();
temp_var.str.clear();
is_generator_working = false;
}
catch(...)
@ -794,7 +789,7 @@ bool Generator<StreamType>::FindInCache(const Item::Function & item_fun,
Item ** item_block,
std::wstring ** variable)
{
if( item_fun.arg >=0 )
if( item_fun.arg >= 0 )
{
empty_argument.clear();
*variable = &empty_argument;
@ -805,7 +800,10 @@ bool Generator<StreamType>::FindInCache(const Item::Function & item_fun,
BlockStack & block_stack = block_stack_tab[block_stack_index-1];
if( size_t(item_fun.arg) < block_stack.args.size() )
*variable = &block_stack.args[item_fun.arg];
{
*variable = &block_stack.args[item_fun.arg].str;
last_res = block_stack.args[item_fun.arg].res;
}
}
return true;
@ -864,26 +862,17 @@ return false;
template<class StreamType>
bool Generator<StreamType>::FindInVariables(const std::wstring & name,
typename Functions<StreamType>::UserFunction ** function,
Item ** item_block,
std::wstring ** variable)
{
Vars::Iterator i = vars.Find(name);
Vars::iterator i = vars.find(name);
if( i != vars.End() )
if( i != vars.end() )
{
Vars::Variable & var = i->second;
Var & var = i->second;
if( var.type == Vars::variable_string )
{
*variable = &var.val;
return true;
}
else
{
// this is an alias to a function or to a block
return FindInFunctionsAndBlocks(var.val, function, item_block);
}
*variable = &var.str;
last_res = var.res;
return true;
}
return false;
@ -906,7 +895,7 @@ bool Generator<StreamType>::Find(const Item::Function & item_fun,
if( FindInFunctionsAndBlocks(item_fun.name, function, item_block) )
return true;
if( FindInVariables(item_fun.name, function, item_block, variable) )
if( FindInVariables(item_fun.name, variable) )
return true;
CreateUnknownMsg(item_fun.name);
@ -937,26 +926,27 @@ void Generator<StreamType>::CallFunction(typename Functions<StreamType>::UserFun
template<class StreamType>
void Generator<StreamType>::CallFunction(typename Functions<StreamType>::UserFunction * function,
std::vector<std::wstring> & params,
std::vector<Var> & parameters,
StreamType & out_stream,
const StreamType & in_stream)
{
if( params.empty() )
if( parameters.empty() )
{
FunInfo<StreamType> info(out_stream, params, empty, in_stream, stack_tab[stack_index-1]);
FunInfo<StreamType> info(out_stream, parameters, empty, in_stream, stack_tab[stack_index-1]);
CallFunction(function, info);
}
else
{
FunInfo<StreamType> info(out_stream, params, params[0], in_stream, stack_tab[stack_index-1]);
FunInfo<StreamType> info(out_stream, parameters, parameters[0].str, in_stream, stack_tab[stack_index-1]);
CallFunction(function, info);
}
}
template<class StreamType>
bool Generator<StreamType>::CallBlock(Item & item_block,
std::vector<std::wstring> & params,
std::vector<Var> & parameters,
StreamType & out_stream)
{
if( block_stack_index >= block_stack_tab.size() )
@ -968,10 +958,8 @@ bool Generator<StreamType>::CallBlock(Item & item_block,
StreamType * old_stream = output_stream;
BlockStack & block_stack = block_stack_tab[block_stack_index];
block_stack.args.resize(params.size());
for(size_t i=0 ; i<params.size() ; ++i)
block_stack.args[i] = params[i]; // or may std::move in the future? (params will not be used anymore)
block_stack.was_return = false;
block_stack.args = parameters;
output_stream = block_stack.out_stream;
ClearStream(*output_stream);
@ -986,8 +974,7 @@ bool Generator<StreamType>::CallBlock(Item & item_block,
#endif
out_stream.write(str.c_str(), str.size());
last_res = !str.empty();
// last_res is set by [return ...] statement
ClearStream(*output_stream);
output_stream = old_stream;
@ -1007,6 +994,7 @@ bool Generator<StreamType>::Call(Item::Function & item_fun,
typename Functions<StreamType>::UserFunction * fun;
Item * item_block;
std::wstring * variable;
std::vector<Var> parameters;
if( clear_out_stream )
ClearStream(out_stream);
@ -1014,57 +1002,40 @@ std::wstring * variable;
if( !Find(item_fun, &fun, &item_block, &variable) )
return false;
parameters.resize(item_fun.parameters.size());
for(size_t i=0 ; i<item_fun.parameters.size() ; ++i)
{
Item::Function & fun_child = *item_fun.parameters[i];
if( !fun_child.name.empty() )
{
StreamType local_temp_stream;
Call(fun_child, local_temp_stream, true, empty_stream);
if( fun || item_block )
{
#ifdef EZC_HAS_SPECIAL_STREAM
fun_child.par = local_temp_stream.Str();
#else
fun_child.par = local_temp_stream.str();
#endif
}
#ifdef EZC_HAS_SPECIAL_STREAM
parameters[i].str = local_temp_stream.Str();
#else
parameters[i].str = local_temp_stream.str();
#endif
// the stream has to be cleared when we finished
ClearStream(local_temp_stream);
parameters[i].res = last_res;
}
}
if( fun || item_block )
{
parameters.resize(item_fun.parameters.size());
for(size_t i=0 ; i<item_fun.parameters.size() ; ++i)
else
{
// in c++11 we can use std::move here
parameters[i] = item_fun.parameters[i]->par;
if( !item_fun.parameters[i]->name.empty() )
item_fun.parameters[i]->par.clear();
parameters[i].str = fun_child.par;
parameters[i].res = !fun_child.par.empty();
}
}
if( fun )
{
CallFunction(fun, parameters, out_stream, in_stream);
}
else
if( item_block )
{
return CallBlock(*item_block, parameters, out_stream);
}
else
if( variable )
{
out_stream.write(variable->c_str(), variable->size());
last_res = !variable->empty();
}
return true;
}
@ -1660,7 +1631,6 @@ void Generator<StreamType>::MakeTextFor(Item & item)
// is_generating_for will be changed by next call to MakeText()
// so we should set it in each iterations
is_generating_for = true;
//Call(function, item.functions[0].params, stream_temp1, true, empty_stream);
Call(item.functions[0], stream_temp1, true, empty_stream);
if( !last_res )
@ -1676,64 +1646,53 @@ void Generator<StreamType>::MakeTextFor(Item & item)
template<class StreamType>
void Generator<StreamType>::MakeTextDefine(Item & item)
{
Item::Function * pfun = 0;
if( !can_use_vars )
{
CreateMsg(L"[def] statement not available");
return;
}
if( item.functions.size() == 1 &&
item.functions[0].parameters.size() == 1 )
{
if( item.functions[0].parameters[0]->name.empty() )
{
// it is [def name "string"]
vars.Insert(item.functions[0].name, Vars::variable_string, item.functions[0].parameters[0]->par);
temp_var.str = item.functions[0].parameters[0]->par;
temp_var.res = !temp_var.str.empty();
vars[item.functions[0].name] = temp_var;
}
else
{
// it is [def name [function]]
if( Call(*item.functions[0].parameters[0], stream_temp_define, true, empty_stream) )
{
#ifdef EZC_HAS_SPECIAL_STREAM
const std::wstring & str = stream_temp_define.Str();
#else
const std::wstring & str = stream_temp_define.str();
#endif
vars.Insert(item.functions[0].name, Vars::variable_string, str);
}
// it is [def name [function "funpar"]]
pfun = item.functions[0].parameters[0];
}
}
else
if( item.functions.size() == 2 &&
item.functions[0].parameters.empty() &&
item.functions[1].parameters.empty() )
{
typename Functions<StreamType>::UserFunction * function;
Item * item_block;
std::wstring * variable;
if( Find(item.functions[1], &function, &item_block, &variable) )
if( item.functions.size() == 2 )
{
// is is [def name function "funpar"]
pfun = &item.functions[1];
}
if( pfun )
{
if( Call(*pfun, stream_temp_define, true, empty_stream) )
{
if( variable )
{
Vars::Iterator i = vars.Find(*variable);
#ifdef EZC_HAS_SPECIAL_STREAM
temp_var.str = stream_temp_define.Str();
#else
temp_var.str = stream_temp_define.str();
#endif
if( i != vars.End() )
{
Vars::Variable & var = i->second;
vars.Insert(*variable, var.type, var.val);
}
}
else
{
vars.Insert(item.functions[0].name, Vars::variable_alias, item.functions[1].name);
}
temp_var.res = last_res;
vars[item.functions[0].name] = temp_var;
}
else
{
CreateMsg(L"[def] unknown function/block/variable", item.functions[1].name.c_str());
CreateMsg(L"[def] unknown function/block/variable", pfun->name);
}
}
}
@ -1853,6 +1812,29 @@ void Generator<StreamType>::MakeTextEzc(Item & item)
}
template<class StreamType>
void Generator<StreamType>::MakeTextReturn(Item & item)
{
last_res = false;
if( block_stack_index == 0 )
{
// the [return] statement is not called from a [block]
CreateMsg(L"[return] should be called from a [block]");
return;
}
BlockStack & block_stack = block_stack_tab[block_stack_index - 1];
block_stack.was_return = true;
if( !item.functions.empty() )
{
// output stream in [return] statement is ignored
// this Call() sets last_res which is used later when we return to CallBlock()
Call(item.functions[0], stream_temp1, false, empty_stream);
ClearStream(stream_temp1);
}
}
template<class StreamType>
@ -1860,21 +1842,29 @@ bool Generator<StreamType>::LimitAchieved()
{
if( break_generating )
return true;
if( ++current_item > max_items )
if( current_item >= max_items )
{
break_generating = true;
CreateMsg(L"Generator exceeded allowed number of elements");
return true;
}
if( ++stack_index > stack_tab.size() )
if( stack_index >= stack_tab.size() )
{
break_generating = true;
CreateMsg(L"Generator exceeded the stack size");
return true;
}
if( block_stack_index > 0 )
{
BlockStack & block_stack = block_stack_tab[block_stack_index - 1];
if( block_stack.was_return )
return true;
}
return false;
}
@ -1885,6 +1875,8 @@ void Generator<StreamType>::MakeText(Item & item)
if( LimitAchieved() )
return;
current_item += 1;
stack_index += 1;
is_generating_for = false;
is_generating_if = false;
is_generating_is = false;
@ -1909,6 +1901,7 @@ void Generator<StreamType>::MakeText(Item & item)
else if( item.type == Item::item_for ) MakeTextFor(item);
else if( item.type == Item::item_filter ) MakeTextFilter(item);
else if( item.type == Item::item_ezc ) MakeTextEzc(item);
else if( item.type == Item::item_return ) MakeTextReturn(item);
else if( item.type == Item::item_err )
CreateMsg(L"a wrong directive");

View File

@ -57,15 +57,17 @@ struct Item
item_none, item_container, item_text, item_normal, item_is, item_isno,
item_if, item_ifno, item_ifany, item_ifone, item_ifanyno, item_ifoneno, item_ifindex,
item_for, item_else, item_end, item_err, item_include, item_comment, item_def, item_filter,
item_ezc, item_block
item_ezc, item_block, item_return
};
struct Function
{
std::wstring name; // function name (can be empty, means there is no any function -- only a text parameter)
std::wstring par; // parameter
std::vector<Function*> parameters;
std::wstring name; // function name (can be empty, means there is no any function -- only
// a text parameter and a boolean value)
std::wstring par; // string parameter
std::vector<Function*> parameters; // if name is not empty then is is a function and can have 'parameters'
// if name is empty then parameters is empty too
void * fun_cache; // only valid if name is not empty
Item * item_block;
int arg; // used if name is numeric (if no then is equal -1)

View File

@ -578,6 +578,7 @@ bool PatternParser::ReadFunction(Item::Function & function)
if( !ReadName(function.name) )
return false;
// !! IMPROVE ME add skiping some white characters (at the beginning and at the end)
if( IsPositiveNumber(function.name) )
function.arg = wcstol(function.name.c_str(), 0, 10);
@ -787,11 +788,11 @@ void PatternParser::ReadDirectiveDef(Item & item)
}
else
if( item.functions.size() == 2 &&
item.functions[0].parameters.empty() && item.functions[1].parameters.empty() )
item.functions[0].parameters.empty() )
{
// it is an alias:
// it is:
// [def name function]
// (name is an alias to a function, to a block or to an other variable)
// or [def name function "funpar1" "funpar2"] etc.
item.type = Item::item_def;
}
@ -814,6 +815,7 @@ void PatternParser::ReadDirectiveEzc(Item & item)
ReadFunctions(item);
}
void PatternParser::ReadDirectiveBlock(Item & item)
{
item.type = Item::item_block;
@ -825,6 +827,16 @@ void PatternParser::ReadDirectiveBlock(Item & item)
}
void PatternParser::ReadDirectiveReturn(Item & item)
{
item.type = Item::item_return;
ReadFunctions(item);
// max one function
if( item.functions.size() > 1 )
item.type = Item::item_err;
}
// user defined directive
void PatternParser::ReadDirectiveNormal(const std::wstring & name, Item & item)
@ -868,6 +880,7 @@ std::wstring name;
else if( name == L"filter" ) ReadDirectiveFilter(item);
else if( name == L"ezc" ) ReadDirectiveEzc(item);
else if( name == L"block" ) ReadDirectiveBlock(item);
else if( name == L"return" ) ReadDirectiveReturn(item);
else if( name == L"#" ) ReadDirectiveComment(item);
else
ReadDirectiveNormal(name, item);
@ -1042,8 +1055,6 @@ void PatternParser::CreateTree(Item & item)
if( pitem->type == Item::item_include )
CreateTreeReadInclude(*pitem);
// item_def is ignored here
}
}

View File

@ -180,6 +180,7 @@ private:
void ReadDirectiveFilter(Item & item);
void ReadDirectiveEzc(Item & item);
void ReadDirectiveBlock(Item & item);
void ReadDirectiveReturn(Item & item);
void ReadDirectiveNormal(const std::wstring & name, Item & item);
void CreateTreeReadItemDirectiveCheckEnding(Item & item);