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:
parent
6bd8889456
commit
0a7bd3159a
|
@ -46,6 +46,16 @@
|
||||||
namespace Ezc
|
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
|
a base class for your own function data class
|
||||||
|
@ -111,16 +121,19 @@ struct Stack
|
||||||
|
|
||||||
// !! IMPROVE ME
|
// !! IMPROVE ME
|
||||||
// the name is bad
|
// the name is bad
|
||||||
// may it should be called Env (environment)
|
// may it should be called Env (environment) or FunEnv
|
||||||
template<class StreamType>
|
template<class StreamType>
|
||||||
struct FunInfo
|
struct FunInfo
|
||||||
{
|
{
|
||||||
|
// a result consists of a string and a boolean value
|
||||||
// output stream
|
// output stream
|
||||||
StreamType & out;
|
StreamType & out;
|
||||||
|
// return value from a user's function (default false if not set directly by the function)
|
||||||
|
bool res;
|
||||||
|
|
||||||
// table of parameters
|
// table of parameters
|
||||||
// the table can be empty
|
// the table can be empty
|
||||||
std::vector<std::wstring> & params;
|
std::vector<Var> & params;
|
||||||
|
|
||||||
// the first parameter
|
// the first parameter
|
||||||
// you can always use it even if there are not any parameters (params is empty)
|
// 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
|
// for other statements than [for] this is always zero
|
||||||
size_t iter;
|
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
|
// arguments: output_stream, table_of_parameters, the_first_parameter
|
||||||
FunInfo(StreamType & o,
|
FunInfo(StreamType & o,
|
||||||
std::vector<std::wstring> & pars,
|
std::vector<Var> & pars,
|
||||||
const std::wstring & first_par,
|
const std::wstring & first_par,
|
||||||
const StreamType & input_stream,
|
const StreamType & input_stream,
|
||||||
Stack & s) : out(o), params(pars), par(first_par), in(input_stream), stack(s)
|
Stack & s) : out(o), params(pars), par(first_par), in(input_stream), stack(s)
|
||||||
|
|
235
src/generator.h
235
src/generator.h
|
@ -39,7 +39,6 @@
|
||||||
#ifndef headerfile_ezc_generator
|
#ifndef headerfile_ezc_generator
|
||||||
#define headerfile_ezc_generator
|
#define headerfile_ezc_generator
|
||||||
|
|
||||||
#include "vars.h"
|
|
||||||
#include "blocks.h"
|
#include "blocks.h"
|
||||||
#include "pattern.h"
|
#include "pattern.h"
|
||||||
#include "functions.h"
|
#include "functions.h"
|
||||||
|
@ -126,10 +125,18 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
||||||
|
// variables set
|
||||||
|
typedef std::map<std::wstring, Var> Vars;
|
||||||
|
Vars vars;
|
||||||
|
|
||||||
|
Var temp_var;
|
||||||
|
|
||||||
struct BlockStack
|
struct BlockStack
|
||||||
{
|
{
|
||||||
std::vector<std::wstring> args;
|
std::vector<Var> args;
|
||||||
StreamType * out_stream;
|
StreamType * out_stream;
|
||||||
|
bool was_return;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<BlockStack> block_stack_tab;
|
std::vector<BlockStack> block_stack_tab;
|
||||||
|
@ -150,23 +157,11 @@ private:
|
||||||
Blocks * pblocks;
|
Blocks * pblocks;
|
||||||
Functions<StreamType> * pfunctions;
|
Functions<StreamType> * pfunctions;
|
||||||
|
|
||||||
// variables set
|
|
||||||
Vars vars;
|
|
||||||
|
|
||||||
// output_tmp_stream is used when outputting to more than one stream
|
// 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
|
// (first we output to output_tmp_stream and then the content is copied
|
||||||
// to the correct streams)
|
// to the correct streams)
|
||||||
StreamType output_tmp_stream;
|
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
|
// pointers to the output streams
|
||||||
std::vector<StreamType*> output_stream_tab;
|
std::vector<StreamType*> output_stream_tab;
|
||||||
|
|
||||||
|
@ -259,8 +254,6 @@ private:
|
||||||
Item ** item_block);
|
Item ** item_block);
|
||||||
|
|
||||||
bool FindInVariables(const std::wstring & name,
|
bool FindInVariables(const std::wstring & name,
|
||||||
typename Functions<StreamType>::UserFunction ** function,
|
|
||||||
Item ** item_block,
|
|
||||||
std::wstring ** variable);
|
std::wstring ** variable);
|
||||||
|
|
||||||
bool Find(const Item::Function & item_fun,
|
bool Find(const Item::Function & item_fun,
|
||||||
|
@ -272,12 +265,12 @@ private:
|
||||||
FunInfo<StreamType> & info);
|
FunInfo<StreamType> & info);
|
||||||
|
|
||||||
void CallFunction(typename Functions<StreamType>::UserFunction * function,
|
void CallFunction(typename Functions<StreamType>::UserFunction * function,
|
||||||
std::vector<std::wstring> & params,
|
std::vector<Var> & parameters,
|
||||||
StreamType & out_stream,
|
StreamType & out_stream,
|
||||||
const StreamType & in_stream);
|
const StreamType & in_stream);
|
||||||
|
|
||||||
bool CallBlock(Item & item_block,
|
bool CallBlock(Item & item_block,
|
||||||
std::vector<std::wstring> & params,
|
std::vector<Var> & parameters,
|
||||||
StreamType & out_stream);
|
StreamType & out_stream);
|
||||||
|
|
||||||
bool Call(Item::Function & item_fun,
|
bool Call(Item::Function & item_fun,
|
||||||
|
@ -325,6 +318,7 @@ private:
|
||||||
void MakeTextDefine(Item & item);
|
void MakeTextDefine(Item & item);
|
||||||
void MakeTextFilter(Item & item);
|
void MakeTextFilter(Item & item);
|
||||||
void MakeTextEzc(Item & item);
|
void MakeTextEzc(Item & item);
|
||||||
|
void MakeTextReturn(Item & item);
|
||||||
void MakeText(Item & item);
|
void MakeText(Item & item);
|
||||||
|
|
||||||
void MakeEzcStream(Item::Function & fun);
|
void MakeEzcStream(Item::Function & fun);
|
||||||
|
@ -729,7 +723,7 @@ void Generator<StreamType>::Generate()
|
||||||
filter_index = 0;
|
filter_index = 0;
|
||||||
stack_index = 0;
|
stack_index = 0;
|
||||||
block_stack_index = 0;
|
block_stack_index = 0;
|
||||||
vars.Clear();
|
vars.clear();
|
||||||
|
|
||||||
if( ppattern )
|
if( ppattern )
|
||||||
{
|
{
|
||||||
|
@ -741,7 +735,8 @@ void Generator<StreamType>::Generate()
|
||||||
if( output_stream_index.size() > 1 )
|
if( output_stream_index.size() > 1 )
|
||||||
WriteTmpStreamToStreams();
|
WriteTmpStreamToStreams();
|
||||||
|
|
||||||
vars.Clear();
|
vars.clear();
|
||||||
|
temp_var.str.clear();
|
||||||
is_generator_working = false;
|
is_generator_working = false;
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
|
@ -794,7 +789,7 @@ bool Generator<StreamType>::FindInCache(const Item::Function & item_fun,
|
||||||
Item ** item_block,
|
Item ** item_block,
|
||||||
std::wstring ** variable)
|
std::wstring ** variable)
|
||||||
{
|
{
|
||||||
if( item_fun.arg >=0 )
|
if( item_fun.arg >= 0 )
|
||||||
{
|
{
|
||||||
empty_argument.clear();
|
empty_argument.clear();
|
||||||
*variable = &empty_argument;
|
*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];
|
BlockStack & block_stack = block_stack_tab[block_stack_index-1];
|
||||||
|
|
||||||
if( size_t(item_fun.arg) < block_stack.args.size() )
|
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;
|
return true;
|
||||||
|
@ -864,26 +862,17 @@ return false;
|
||||||
|
|
||||||
template<class StreamType>
|
template<class StreamType>
|
||||||
bool Generator<StreamType>::FindInVariables(const std::wstring & name,
|
bool Generator<StreamType>::FindInVariables(const std::wstring & name,
|
||||||
typename Functions<StreamType>::UserFunction ** function,
|
|
||||||
Item ** item_block,
|
|
||||||
std::wstring ** variable)
|
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.str;
|
||||||
{
|
last_res = var.res;
|
||||||
*variable = &var.val;
|
return true;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// this is an alias to a function or to a block
|
|
||||||
return FindInFunctionsAndBlocks(var.val, function, item_block);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -906,7 +895,7 @@ bool Generator<StreamType>::Find(const Item::Function & item_fun,
|
||||||
if( FindInFunctionsAndBlocks(item_fun.name, function, item_block) )
|
if( FindInFunctionsAndBlocks(item_fun.name, function, item_block) )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if( FindInVariables(item_fun.name, function, item_block, variable) )
|
if( FindInVariables(item_fun.name, variable) )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
CreateUnknownMsg(item_fun.name);
|
CreateUnknownMsg(item_fun.name);
|
||||||
|
@ -937,26 +926,27 @@ void Generator<StreamType>::CallFunction(typename Functions<StreamType>::UserFun
|
||||||
|
|
||||||
template<class StreamType>
|
template<class StreamType>
|
||||||
void Generator<StreamType>::CallFunction(typename Functions<StreamType>::UserFunction * function,
|
void Generator<StreamType>::CallFunction(typename Functions<StreamType>::UserFunction * function,
|
||||||
std::vector<std::wstring> & params,
|
std::vector<Var> & parameters,
|
||||||
StreamType & out_stream,
|
StreamType & out_stream,
|
||||||
const StreamType & in_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);
|
CallFunction(function, info);
|
||||||
}
|
}
|
||||||
else
|
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);
|
CallFunction(function, info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template<class StreamType>
|
template<class StreamType>
|
||||||
bool Generator<StreamType>::CallBlock(Item & item_block,
|
bool Generator<StreamType>::CallBlock(Item & item_block,
|
||||||
std::vector<std::wstring> & params,
|
std::vector<Var> & parameters,
|
||||||
StreamType & out_stream)
|
StreamType & out_stream)
|
||||||
{
|
{
|
||||||
if( block_stack_index >= block_stack_tab.size() )
|
if( block_stack_index >= block_stack_tab.size() )
|
||||||
|
@ -968,10 +958,8 @@ bool Generator<StreamType>::CallBlock(Item & item_block,
|
||||||
StreamType * old_stream = output_stream;
|
StreamType * old_stream = output_stream;
|
||||||
BlockStack & block_stack = block_stack_tab[block_stack_index];
|
BlockStack & block_stack = block_stack_tab[block_stack_index];
|
||||||
|
|
||||||
block_stack.args.resize(params.size());
|
block_stack.was_return = false;
|
||||||
|
block_stack.args = parameters;
|
||||||
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)
|
|
||||||
|
|
||||||
output_stream = block_stack.out_stream;
|
output_stream = block_stack.out_stream;
|
||||||
ClearStream(*output_stream);
|
ClearStream(*output_stream);
|
||||||
|
@ -986,8 +974,7 @@ bool Generator<StreamType>::CallBlock(Item & item_block,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
out_stream.write(str.c_str(), str.size());
|
out_stream.write(str.c_str(), str.size());
|
||||||
|
// last_res is set by [return ...] statement
|
||||||
last_res = !str.empty();
|
|
||||||
|
|
||||||
ClearStream(*output_stream);
|
ClearStream(*output_stream);
|
||||||
output_stream = old_stream;
|
output_stream = old_stream;
|
||||||
|
@ -1007,6 +994,7 @@ bool Generator<StreamType>::Call(Item::Function & item_fun,
|
||||||
typename Functions<StreamType>::UserFunction * fun;
|
typename Functions<StreamType>::UserFunction * fun;
|
||||||
Item * item_block;
|
Item * item_block;
|
||||||
std::wstring * variable;
|
std::wstring * variable;
|
||||||
|
std::vector<Var> parameters;
|
||||||
|
|
||||||
if( clear_out_stream )
|
if( clear_out_stream )
|
||||||
ClearStream(out_stream);
|
ClearStream(out_stream);
|
||||||
|
@ -1014,57 +1002,40 @@ std::wstring * variable;
|
||||||
if( !Find(item_fun, &fun, &item_block, &variable) )
|
if( !Find(item_fun, &fun, &item_block, &variable) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
parameters.resize(item_fun.parameters.size());
|
||||||
|
|
||||||
for(size_t i=0 ; i<item_fun.parameters.size() ; ++i)
|
for(size_t i=0 ; i<item_fun.parameters.size() ; ++i)
|
||||||
{
|
{
|
||||||
Item::Function & fun_child = *item_fun.parameters[i];
|
Item::Function & fun_child = *item_fun.parameters[i];
|
||||||
|
|
||||||
if( !fun_child.name.empty() )
|
if( !fun_child.name.empty() )
|
||||||
{
|
{
|
||||||
|
StreamType local_temp_stream;
|
||||||
Call(fun_child, local_temp_stream, true, empty_stream);
|
Call(fun_child, local_temp_stream, true, empty_stream);
|
||||||
|
|
||||||
if( fun || item_block )
|
#ifdef EZC_HAS_SPECIAL_STREAM
|
||||||
{
|
parameters[i].str = local_temp_stream.Str();
|
||||||
#ifdef EZC_HAS_SPECIAL_STREAM
|
#else
|
||||||
fun_child.par = local_temp_stream.Str();
|
parameters[i].str = local_temp_stream.str();
|
||||||
#else
|
#endif
|
||||||
fun_child.par = local_temp_stream.str();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// the stream has to be cleared when we finished
|
parameters[i].res = last_res;
|
||||||
ClearStream(local_temp_stream);
|
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
|
||||||
if( fun || item_block )
|
|
||||||
{
|
|
||||||
parameters.resize(item_fun.parameters.size());
|
|
||||||
|
|
||||||
for(size_t i=0 ; i<item_fun.parameters.size() ; ++i)
|
|
||||||
{
|
{
|
||||||
// in c++11 we can use std::move here
|
parameters[i].str = fun_child.par;
|
||||||
parameters[i] = item_fun.parameters[i]->par;
|
parameters[i].res = !fun_child.par.empty();
|
||||||
|
|
||||||
if( !item_fun.parameters[i]->name.empty() )
|
|
||||||
item_fun.parameters[i]->par.clear();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( fun )
|
if( fun )
|
||||||
{
|
|
||||||
CallFunction(fun, parameters, out_stream, in_stream);
|
CallFunction(fun, parameters, out_stream, in_stream);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
if( item_block )
|
if( item_block )
|
||||||
{
|
|
||||||
return CallBlock(*item_block, parameters, out_stream);
|
return CallBlock(*item_block, parameters, out_stream);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
if( variable )
|
if( variable )
|
||||||
{
|
|
||||||
out_stream.write(variable->c_str(), variable->size());
|
out_stream.write(variable->c_str(), variable->size());
|
||||||
last_res = !variable->empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1660,7 +1631,6 @@ void Generator<StreamType>::MakeTextFor(Item & item)
|
||||||
// is_generating_for will be changed by next call to MakeText()
|
// is_generating_for will be changed by next call to MakeText()
|
||||||
// so we should set it in each iterations
|
// so we should set it in each iterations
|
||||||
is_generating_for = true;
|
is_generating_for = true;
|
||||||
//Call(function, item.functions[0].params, stream_temp1, true, empty_stream);
|
|
||||||
Call(item.functions[0], stream_temp1, true, empty_stream);
|
Call(item.functions[0], stream_temp1, true, empty_stream);
|
||||||
|
|
||||||
if( !last_res )
|
if( !last_res )
|
||||||
|
@ -1676,64 +1646,53 @@ void Generator<StreamType>::MakeTextFor(Item & item)
|
||||||
template<class StreamType>
|
template<class StreamType>
|
||||||
void Generator<StreamType>::MakeTextDefine(Item & item)
|
void Generator<StreamType>::MakeTextDefine(Item & item)
|
||||||
{
|
{
|
||||||
|
Item::Function * pfun = 0;
|
||||||
|
|
||||||
if( !can_use_vars )
|
if( !can_use_vars )
|
||||||
{
|
{
|
||||||
CreateMsg(L"[def] statement not available");
|
CreateMsg(L"[def] statement not available");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( item.functions.size() == 1 &&
|
if( item.functions.size() == 1 &&
|
||||||
item.functions[0].parameters.size() == 1 )
|
item.functions[0].parameters.size() == 1 )
|
||||||
{
|
{
|
||||||
if( item.functions[0].parameters[0]->name.empty() )
|
if( item.functions[0].parameters[0]->name.empty() )
|
||||||
{
|
{
|
||||||
// it is [def name "string"]
|
// 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
|
else
|
||||||
{
|
{
|
||||||
// it is [def name [function]]
|
// it is [def name [function "funpar"]]
|
||||||
if( Call(*item.functions[0].parameters[0], stream_temp_define, true, empty_stream) )
|
pfun = item.functions[0].parameters[0];
|
||||||
{
|
|
||||||
#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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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 )
|
#ifdef EZC_HAS_SPECIAL_STREAM
|
||||||
{
|
temp_var.str = stream_temp_define.Str();
|
||||||
Vars::Iterator i = vars.Find(*variable);
|
#else
|
||||||
|
temp_var.str = stream_temp_define.str();
|
||||||
|
#endif
|
||||||
|
|
||||||
if( i != vars.End() )
|
temp_var.res = last_res;
|
||||||
{
|
vars[item.functions[0].name] = temp_var;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
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>
|
template<class StreamType>
|
||||||
|
@ -1860,21 +1842,29 @@ bool Generator<StreamType>::LimitAchieved()
|
||||||
{
|
{
|
||||||
if( break_generating )
|
if( break_generating )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if( ++current_item > max_items )
|
if( current_item >= max_items )
|
||||||
{
|
{
|
||||||
break_generating = true;
|
break_generating = true;
|
||||||
CreateMsg(L"Generator exceeded allowed number of elements");
|
CreateMsg(L"Generator exceeded allowed number of elements");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( ++stack_index > stack_tab.size() )
|
if( stack_index >= stack_tab.size() )
|
||||||
{
|
{
|
||||||
break_generating = true;
|
break_generating = true;
|
||||||
CreateMsg(L"Generator exceeded the stack size");
|
CreateMsg(L"Generator exceeded the stack size");
|
||||||
return true;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1885,6 +1875,8 @@ void Generator<StreamType>::MakeText(Item & item)
|
||||||
if( LimitAchieved() )
|
if( LimitAchieved() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
current_item += 1;
|
||||||
|
stack_index += 1;
|
||||||
is_generating_for = false;
|
is_generating_for = false;
|
||||||
is_generating_if = false;
|
is_generating_if = false;
|
||||||
is_generating_is = 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_for ) MakeTextFor(item);
|
||||||
else if( item.type == Item::item_filter ) MakeTextFilter(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_ezc ) MakeTextEzc(item);
|
||||||
|
else if( item.type == Item::item_return ) MakeTextReturn(item);
|
||||||
else if( item.type == Item::item_err )
|
else if( item.type == Item::item_err )
|
||||||
CreateMsg(L"a wrong directive");
|
CreateMsg(L"a wrong directive");
|
||||||
|
|
||||||
|
|
10
src/item.h
10
src/item.h
|
@ -57,15 +57,17 @@ struct Item
|
||||||
item_none, item_container, item_text, item_normal, item_is, item_isno,
|
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_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_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
|
struct Function
|
||||||
{
|
{
|
||||||
std::wstring name; // function name (can be empty, means there is no any function -- only a text parameter)
|
std::wstring name; // function name (can be empty, means there is no any function -- only
|
||||||
std::wstring par; // parameter
|
// a text parameter and a boolean value)
|
||||||
std::vector<Function*> parameters;
|
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
|
void * fun_cache; // only valid if name is not empty
|
||||||
Item * item_block;
|
Item * item_block;
|
||||||
int arg; // used if name is numeric (if no then is equal -1)
|
int arg; // used if name is numeric (if no then is equal -1)
|
||||||
|
|
|
@ -578,6 +578,7 @@ bool PatternParser::ReadFunction(Item::Function & function)
|
||||||
if( !ReadName(function.name) )
|
if( !ReadName(function.name) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// !! IMPROVE ME add skiping some white characters (at the beginning and at the end)
|
||||||
if( IsPositiveNumber(function.name) )
|
if( IsPositiveNumber(function.name) )
|
||||||
function.arg = wcstol(function.name.c_str(), 0, 10);
|
function.arg = wcstol(function.name.c_str(), 0, 10);
|
||||||
|
|
||||||
|
@ -787,11 +788,11 @@ void PatternParser::ReadDirectiveDef(Item & item)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if( item.functions.size() == 2 &&
|
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]
|
// [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;
|
item.type = Item::item_def;
|
||||||
}
|
}
|
||||||
|
@ -814,6 +815,7 @@ void PatternParser::ReadDirectiveEzc(Item & item)
|
||||||
ReadFunctions(item);
|
ReadFunctions(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PatternParser::ReadDirectiveBlock(Item & item)
|
void PatternParser::ReadDirectiveBlock(Item & item)
|
||||||
{
|
{
|
||||||
item.type = Item::item_block;
|
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
|
// user defined directive
|
||||||
void PatternParser::ReadDirectiveNormal(const std::wstring & name, Item & item)
|
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"filter" ) ReadDirectiveFilter(item);
|
||||||
else if( name == L"ezc" ) ReadDirectiveEzc(item);
|
else if( name == L"ezc" ) ReadDirectiveEzc(item);
|
||||||
else if( name == L"block" ) ReadDirectiveBlock(item);
|
else if( name == L"block" ) ReadDirectiveBlock(item);
|
||||||
|
else if( name == L"return" ) ReadDirectiveReturn(item);
|
||||||
else if( name == L"#" ) ReadDirectiveComment(item);
|
else if( name == L"#" ) ReadDirectiveComment(item);
|
||||||
else
|
else
|
||||||
ReadDirectiveNormal(name, item);
|
ReadDirectiveNormal(name, item);
|
||||||
|
@ -1042,8 +1055,6 @@ void PatternParser::CreateTree(Item & item)
|
||||||
|
|
||||||
if( pitem->type == Item::item_include )
|
if( pitem->type == Item::item_include )
|
||||||
CreateTreeReadInclude(*pitem);
|
CreateTreeReadInclude(*pitem);
|
||||||
|
|
||||||
// item_def is ignored here
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -180,6 +180,7 @@ private:
|
||||||
void ReadDirectiveFilter(Item & item);
|
void ReadDirectiveFilter(Item & item);
|
||||||
void ReadDirectiveEzc(Item & item);
|
void ReadDirectiveEzc(Item & item);
|
||||||
void ReadDirectiveBlock(Item & item);
|
void ReadDirectiveBlock(Item & item);
|
||||||
|
void ReadDirectiveReturn(Item & item);
|
||||||
void ReadDirectiveNormal(const std::wstring & name, Item & item);
|
void ReadDirectiveNormal(const std::wstring & name, Item & item);
|
||||||
|
|
||||||
void CreateTreeReadItemDirectiveCheckEnding(Item & item);
|
void CreateTreeReadItemDirectiveCheckEnding(Item & item);
|
||||||
|
|
Loading…
Reference in New Issue