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:
+114
-121
@@ -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");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user