changed semantic of [def] statements:
- [def] is used to define a variable (like before) but if we assign a string such as [def var "string"] the string is evaluated to bool in a different way: empty string is false, not empty string is true - added [def?] statement - similar like [def] but define a variable only if such a variable is not already defined - added [let] statement - similar like [def] but with lazy evaluation (it is an alias to a function) if it is called to assign a string e.g. [let var "string"] then this has the same meaning like [def] - an alias is only created when we assign a function e.g. [let var my_function] both [def] and [let] are using the same Vars object - added [let?] - make an alias but only if such a variable is not already defined - a std::map of variables moved outside of Generator added method void SetVariables(Vars & variables); - fixed: a result status was not correctly propagated when evaluating [def] statements, this was in Call(...) function: last_res from variables was set in Find() but later was overwritten by Call(...) called for parameters (recursively)
This commit is contained in:
parent
6f6df9524c
commit
0ac8e05c04
|
@ -20,13 +20,13 @@ $(libname): $(o)
|
||||||
|
|
||||||
|
|
||||||
%.o: %.cpp
|
%.o: %.cpp
|
||||||
$(CXX) -c $(CXXFLAGS) -I$(GLOBAL_WORKING_DIR)/pikotools $<
|
$(CXX) -c $(CXXFLAGS) -I$(GLOBAL_WORKING_DIR)/pikotools/src $<
|
||||||
|
|
||||||
|
|
||||||
depend:
|
depend:
|
||||||
# !! IMPROVE ME
|
# !! IMPROVE ME
|
||||||
# as Ezc is a different project we rather shoudn't use '-I$(global_relative_working_dir)/pikotools' here?
|
# as Ezc is a different project we rather shoudn't use '-I$(global_relative_working_dir)/pikotools' here?
|
||||||
makedepend -Y. -I$(global_relative_working_dir)/pikotools -f- *.cpp > Makefile.dep
|
makedepend -Y. -I$(global_relative_working_dir)/pikotools/src -f- *.cpp > Makefile.dep
|
||||||
echo -n "o = " > Makefile.o.dep
|
echo -n "o = " > Makefile.o.dep
|
||||||
ls -1 *.cpp | xargs -I foo echo -n foo " " | sed -E "s/([^\.]*)\.cpp[ ]/\1\.o/g" >> Makefile.o.dep
|
ls -1 *.cpp | xargs -I foo echo -n foo " " | sed -E "s/([^\.]*)\.cpp[ ]/\1\.o/g" >> Makefile.o.dep
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#define headerfile_ezc_funinfo
|
#define headerfile_ezc_funinfo
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
#include "item.h"
|
#include "item.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -52,11 +53,27 @@ namespace Ezc
|
||||||
*/
|
*/
|
||||||
struct Var
|
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
|
std::wstring str; // a string value
|
||||||
bool res; // a boolean value
|
bool res; // a boolean value
|
||||||
|
|
||||||
|
Var()
|
||||||
|
{
|
||||||
|
res = false;
|
||||||
|
is_function = false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef std::map<std::wstring, Var> Vars;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
a base class for your own function data class
|
a base class for your own function data class
|
||||||
|
|
337
src/generator.h
337
src/generator.h
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2007-2018, Tomasz Sowa
|
* Copyright (c) 2007-2021, Tomasz Sowa
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -73,6 +73,7 @@ public:
|
||||||
void SetBlocks(Blocks & blocks);
|
void SetBlocks(Blocks & blocks);
|
||||||
void SetFunctions(Functions<StreamType> & functions);
|
void SetFunctions(Functions<StreamType> & functions);
|
||||||
void SetObjects(Objects<StreamType> & objects);
|
void SetObjects(Objects<StreamType> & objects);
|
||||||
|
void SetVariables(Vars & variables); // [def] and [let]
|
||||||
|
|
||||||
|
|
||||||
void SetMax(size_t max_items_, size_t max_for_items_);
|
void SetMax(size_t max_items_, size_t max_for_items_);
|
||||||
|
@ -131,11 +132,6 @@ public:
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
||||||
// variables set
|
|
||||||
typedef std::map<std::wstring, Var> Vars;
|
|
||||||
Vars vars;
|
|
||||||
|
|
||||||
|
|
||||||
struct BlockStack
|
struct BlockStack
|
||||||
{
|
{
|
||||||
std::vector<Var> args;
|
std::vector<Var> args;
|
||||||
|
@ -155,6 +151,7 @@ private:
|
||||||
Blocks * pblocks;
|
Blocks * pblocks;
|
||||||
Functions<StreamType> * pfunctions;
|
Functions<StreamType> * pfunctions;
|
||||||
Objects<StreamType> * pobjects;
|
Objects<StreamType> * pobjects;
|
||||||
|
Vars * pvars;
|
||||||
|
|
||||||
// pointer to the output streams map (can be null)
|
// pointer to the output streams map (can be null)
|
||||||
// output stream will be created when [ezc out "stream_name"] statement is found
|
// output stream will be created when [ezc out "stream_name"] statement is found
|
||||||
|
@ -185,9 +182,6 @@ private:
|
||||||
std::vector<StreamType*> ezc_out_stack_tab;
|
std::vector<StreamType*> ezc_out_stack_tab;
|
||||||
const StreamType empty_stream;
|
const StreamType empty_stream;
|
||||||
|
|
||||||
// used in [0] [1] [2] when there is no such argument defined
|
|
||||||
std::wstring empty_argument;
|
|
||||||
|
|
||||||
// temporary streams used in [if..] [for...] or [def ...]
|
// temporary streams used in [if..] [for...] or [def ...]
|
||||||
// or if output_stream is null and an ezc function should be called
|
// or if output_stream is null and an ezc function should be called
|
||||||
StreamType stream_temp1, stream_temp_define;
|
StreamType stream_temp1, stream_temp_define;
|
||||||
|
@ -242,7 +236,7 @@ private:
|
||||||
CharType ToLower(CharType c);
|
CharType ToLower(CharType c);
|
||||||
|
|
||||||
|
|
||||||
bool CheckBlockArgument(Item::Function & item_fun, std::wstring ** variable);
|
bool CheckBlockArgument(int arg_index, Var ** variable);
|
||||||
|
|
||||||
bool FindInCache(Item::Function & item_fun,
|
bool FindInCache(Item::Function & item_fun,
|
||||||
BaseObj<StreamType> ** base_obj,
|
BaseObj<StreamType> ** base_obj,
|
||||||
|
@ -257,15 +251,16 @@ private:
|
||||||
Item ** item_block);
|
Item ** item_block);
|
||||||
|
|
||||||
bool FindInVariables(const std::wstring & name,
|
bool FindInVariables(const std::wstring & name,
|
||||||
std::wstring ** variable);
|
Var ** variable);
|
||||||
|
|
||||||
|
|
||||||
bool Find(Item::Function & item_fun,
|
bool Find(Item::Function & item_fun,
|
||||||
|
std::wstring * fun_name,
|
||||||
BaseObj<StreamType> ** base_obj,
|
BaseObj<StreamType> ** base_obj,
|
||||||
int * method_index,
|
int * method_index,
|
||||||
typename Functions<StreamType>::UserFunction ** function,
|
typename Functions<StreamType>::UserFunction ** function,
|
||||||
Item ** item_block,
|
Item ** item_block,
|
||||||
std::wstring ** variable);
|
Var ** variable);
|
||||||
|
|
||||||
void CallFunction(typename Functions<StreamType>::UserFunction * function,
|
void CallFunction(typename Functions<StreamType>::UserFunction * function,
|
||||||
FunInfo<StreamType> & info);
|
FunInfo<StreamType> & info);
|
||||||
|
@ -289,8 +284,14 @@ private:
|
||||||
StreamType & out_stream,
|
StreamType & out_stream,
|
||||||
const StreamType & in_stream);
|
const StreamType & in_stream);
|
||||||
|
|
||||||
|
bool CallVariable(Item::Function & item_fun,
|
||||||
|
Var * variable,
|
||||||
|
std::vector<Var> & parameters,
|
||||||
|
StreamType & out_stream,
|
||||||
|
const StreamType & in_stream);
|
||||||
|
|
||||||
bool Call(Item::Function & item_fun,
|
bool Call(Item::Function & item_fun,
|
||||||
|
std::wstring * fun_name,
|
||||||
StreamType & out_stream,
|
StreamType & out_stream,
|
||||||
bool clear_out_stream,
|
bool clear_out_stream,
|
||||||
const StreamType & in_stream);
|
const StreamType & in_stream);
|
||||||
|
@ -324,7 +325,12 @@ private:
|
||||||
void MakeItemText(Item & item);
|
void MakeItemText(Item & item);
|
||||||
void MakeTextContainer(Item & item);
|
void MakeTextContainer(Item & item);
|
||||||
void MakeTextNormal(Item & item);
|
void MakeTextNormal(Item & item);
|
||||||
|
void MakeTextDefine(Item & item, Var & var);
|
||||||
void MakeTextDefine(Item & item);
|
void MakeTextDefine(Item & item);
|
||||||
|
void MakeTextDefineIfNotSet(Item & item);
|
||||||
|
void MakeTextLet(Item & item, Var & var);
|
||||||
|
void MakeTextLet(Item & item);
|
||||||
|
void MakeTextLetIfNotSet(Item & item);
|
||||||
void MakeTextFilter(Item & item);
|
void MakeTextFilter(Item & item);
|
||||||
void MakeTextEzc(Item & item);
|
void MakeTextEzc(Item & item);
|
||||||
void MakeTextReturn(Item & item);
|
void MakeTextReturn(Item & item);
|
||||||
|
@ -349,6 +355,7 @@ Generator<StreamType>::Generator() : empty_stream()
|
||||||
pblocks = 0;
|
pblocks = 0;
|
||||||
pfunctions = 0;
|
pfunctions = 0;
|
||||||
pobjects = 0;
|
pobjects = 0;
|
||||||
|
pvars = 0;
|
||||||
|
|
||||||
max_items = 50000;
|
max_items = 50000;
|
||||||
max_for_items = 5000;
|
max_for_items = 5000;
|
||||||
|
@ -382,6 +389,7 @@ Generator<StreamType> & Generator<StreamType>::operator=(const Generator<StreamT
|
||||||
pblocks = n.pblocks;
|
pblocks = n.pblocks;
|
||||||
pfunctions = n.pfunctions;
|
pfunctions = n.pfunctions;
|
||||||
pobjects = n.pobjects;
|
pobjects = n.pobjects;
|
||||||
|
pvars = n.pvars;
|
||||||
|
|
||||||
max_items = n.max_items;
|
max_items = n.max_items;
|
||||||
max_for_items = n.max_for_items;
|
max_for_items = n.max_for_items;
|
||||||
|
@ -491,6 +499,14 @@ void Generator<StreamType>::SetObjects(Objects<StreamType> & objects)
|
||||||
pobjects = &objects;
|
pobjects = &objects;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class StreamType>
|
||||||
|
void Generator<StreamType>::SetVariables(Vars & variables)
|
||||||
|
{
|
||||||
|
pvars = &variables;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template<class StreamType>
|
template<class StreamType>
|
||||||
void Generator<StreamType>::CanUseCache(bool can_use_cache)
|
void Generator<StreamType>::CanUseCache(bool can_use_cache)
|
||||||
{
|
{
|
||||||
|
@ -679,10 +695,7 @@ return c;
|
||||||
template<class StreamType>
|
template<class StreamType>
|
||||||
bool Generator<StreamType>::ConvertToBool(const std::wstring & str)
|
bool Generator<StreamType>::ConvertToBool(const std::wstring & str)
|
||||||
{
|
{
|
||||||
if( str == L"true" )
|
return !str.empty();
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -756,7 +769,6 @@ 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();
|
|
||||||
|
|
||||||
if( ppattern )
|
if( ppattern )
|
||||||
{
|
{
|
||||||
|
@ -766,7 +778,6 @@ void Generator<StreamType>::Generate()
|
||||||
MakeText( ppattern->item_root );
|
MakeText( ppattern->item_root );
|
||||||
// !! IMPROVE ME we can print an error message if the stacks are not empty
|
// !! IMPROVE ME we can print an error message if the stacks are not empty
|
||||||
// (some [end] statements has been omited)
|
// (some [end] statements has been omited)
|
||||||
vars.clear();
|
|
||||||
is_generator_working = false;
|
is_generator_working = false;
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
|
@ -808,28 +819,24 @@ void Generator<StreamType>::Generate(OutStreams<StreamType> & out_streams)
|
||||||
|
|
||||||
|
|
||||||
template<class StreamType>
|
template<class StreamType>
|
||||||
bool Generator<StreamType>::CheckBlockArgument(Item::Function & item_fun, std::wstring ** variable)
|
bool Generator<StreamType>::CheckBlockArgument(int arg_index, Var ** variable)
|
||||||
{
|
{
|
||||||
if( item_fun.arg < 0 )
|
if( arg_index < 0 )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
empty_argument.clear();
|
|
||||||
*variable = &empty_argument;
|
|
||||||
last_res = ConvertToBool(empty_argument);
|
|
||||||
|
|
||||||
// it's a numeric function -- an argument to a block e.g.: [1]
|
// it's a numeric function -- an argument to a block e.g.: [1]
|
||||||
if( block_stack_index > 0 )
|
if( block_stack_index > 0 )
|
||||||
{
|
{
|
||||||
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(arg_index) < block_stack.args.size() )
|
||||||
{
|
{
|
||||||
*variable = &block_stack.args[item_fun.arg].str;
|
*variable = &block_stack.args[arg_index];
|
||||||
last_res = block_stack.args[item_fun.arg].res;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -914,50 +921,58 @@ return false;
|
||||||
|
|
||||||
template<class StreamType>
|
template<class StreamType>
|
||||||
bool Generator<StreamType>::FindInVariables(const std::wstring & name,
|
bool Generator<StreamType>::FindInVariables(const std::wstring & name,
|
||||||
std::wstring ** variable)
|
Var ** variable)
|
||||||
{
|
{
|
||||||
Vars::iterator i = vars.find(name);
|
if( pvars )
|
||||||
|
|
||||||
if( i != vars.end() )
|
|
||||||
{
|
{
|
||||||
Var & var = i->second;
|
Vars::iterator i = pvars->find(name);
|
||||||
|
|
||||||
*variable = &var.str;
|
if( i != pvars->end() )
|
||||||
last_res = var.res;
|
{
|
||||||
return true;
|
*variable = &(i->second);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* fun_name can be null, it is used only with [let ...] statements
|
||||||
|
* and if not null then means: as a funcion name we are not using item_fun.name but fun_name
|
||||||
|
*/
|
||||||
template<class StreamType>
|
template<class StreamType>
|
||||||
bool Generator<StreamType>::Find(Item::Function & item_fun,
|
bool Generator<StreamType>::Find(Item::Function & item_fun,
|
||||||
|
std::wstring * fun_name,
|
||||||
BaseObj<StreamType> ** base_obj,
|
BaseObj<StreamType> ** base_obj,
|
||||||
int * method_index,
|
int * method_index,
|
||||||
typename Functions<StreamType>::UserFunction ** function,
|
typename Functions<StreamType>::UserFunction ** function,
|
||||||
Item ** item_block,
|
Item ** item_block,
|
||||||
std::wstring ** variable)
|
Var ** variable)
|
||||||
{
|
{
|
||||||
*base_obj = 0;
|
*base_obj = nullptr;
|
||||||
*method_index = -1;
|
*method_index = -1;
|
||||||
*function = 0;
|
*function = nullptr;
|
||||||
*item_block = 0;
|
*item_block = nullptr;
|
||||||
*variable = 0;
|
*variable = nullptr;
|
||||||
|
|
||||||
if( CheckBlockArgument(item_fun, variable) )
|
if( CheckBlockArgument(item_fun.arg, variable) )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if( FindInCache(item_fun, base_obj, method_index, function, item_block) )
|
if( FindInCache(item_fun, base_obj, method_index, function, item_block) )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if( FindInFunctionsAndBlocks(item_fun.name, base_obj, method_index, function, item_block) )
|
if( !fun_name )
|
||||||
|
fun_name = &item_fun.name;
|
||||||
|
|
||||||
|
if( FindInFunctionsAndBlocks(*fun_name, base_obj, method_index, function, item_block) )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if( FindInVariables(item_fun.name, variable) )
|
if( FindInVariables(*fun_name, variable) )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
CreateUnknownMsg(item_fun.name);
|
CreateUnknownMsg(*fun_name);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1089,9 +1104,32 @@ return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// return: true if a function, variable or block was found and called
|
|
||||||
|
template<class StreamType>
|
||||||
|
bool Generator<StreamType>::CallVariable(Item::Function & item_fun, Var * variable, std::vector<Var> & parameters, StreamType & out_stream, const StreamType & in_stream)
|
||||||
|
{
|
||||||
|
if( variable->is_function )
|
||||||
|
{
|
||||||
|
return Call(item_fun, &variable->str, out_stream, false, in_stream);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out_stream << variable->str;
|
||||||
|
last_res = variable->res;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* return: true if a function, variable or block was found and called (evaluated)
|
||||||
|
*/
|
||||||
template<class StreamType>
|
template<class StreamType>
|
||||||
bool Generator<StreamType>::Call(Item::Function & item_fun,
|
bool Generator<StreamType>::Call(Item::Function & item_fun,
|
||||||
|
std::wstring * fun_name,
|
||||||
StreamType & out_stream,
|
StreamType & out_stream,
|
||||||
bool clear_out_stream,
|
bool clear_out_stream,
|
||||||
const StreamType & in_stream)
|
const StreamType & in_stream)
|
||||||
|
@ -1100,13 +1138,13 @@ BaseObj<StreamType> * base_obj;
|
||||||
int method_index;
|
int method_index;
|
||||||
typename Functions<StreamType>::UserFunction * fun;
|
typename Functions<StreamType>::UserFunction * fun;
|
||||||
Item * item_block;
|
Item * item_block;
|
||||||
std::wstring * variable;
|
Var * variable;
|
||||||
std::vector<Var> parameters;
|
std::vector<Var> parameters;
|
||||||
|
|
||||||
if( clear_out_stream )
|
if( clear_out_stream )
|
||||||
ClearStream(out_stream);
|
ClearStream(out_stream);
|
||||||
|
|
||||||
if( !Find(item_fun, &base_obj, &method_index, &fun, &item_block, &variable) )
|
if( !Find(item_fun, fun_name, &base_obj, &method_index, &fun, &item_block, &variable) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
parameters.resize(item_fun.parameters.size());
|
parameters.resize(item_fun.parameters.size());
|
||||||
|
@ -1118,7 +1156,7 @@ std::vector<Var> parameters;
|
||||||
if( fun_child.is_function )
|
if( fun_child.is_function )
|
||||||
{
|
{
|
||||||
StreamType local_temp_stream;
|
StreamType local_temp_stream;
|
||||||
Call(fun_child, local_temp_stream, true, empty_stream);
|
Call(fun_child, nullptr, local_temp_stream, true, empty_stream);
|
||||||
|
|
||||||
#ifdef EZC_HAS_SPECIAL_STREAM
|
#ifdef EZC_HAS_SPECIAL_STREAM
|
||||||
parameters[i].str = local_temp_stream.Str();
|
parameters[i].str = local_temp_stream.Str();
|
||||||
|
@ -1145,9 +1183,9 @@ std::vector<Var> parameters;
|
||||||
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());
|
return CallVariable(item_fun, variable, parameters, out_stream, in_stream);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1156,7 +1194,7 @@ return true;
|
||||||
template<class StreamType>
|
template<class StreamType>
|
||||||
bool Generator<StreamType>::Call(Item::Function & item_fun)
|
bool Generator<StreamType>::Call(Item::Function & item_fun)
|
||||||
{
|
{
|
||||||
return Call(item_fun, stream_temp1, true, empty_stream);
|
return Call(item_fun, nullptr, stream_temp1, true, empty_stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1529,11 +1567,11 @@ void Generator<StreamType>::MakeTextNormal(Item & item)
|
||||||
{
|
{
|
||||||
if( output_stream )
|
if( output_stream )
|
||||||
{
|
{
|
||||||
Call(item.function, *output_stream, false, empty_stream);
|
Call(item.function, nullptr, *output_stream, false, empty_stream);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Call(item.function, stream_temp1, false, empty_stream);
|
Call(item.function, nullptr, stream_temp1, false, empty_stream);
|
||||||
ClearStream(stream_temp1);
|
ClearStream(stream_temp1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1604,7 +1642,7 @@ void Generator<StreamType>::MakeTextFor(Item & item)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Call(item.function, stream_temp1, true, empty_stream);
|
Call(item.function, nullptr, stream_temp1, true, empty_stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !last_res )
|
if( !last_res )
|
||||||
|
@ -1616,51 +1654,151 @@ void Generator<StreamType>::MakeTextFor(Item & item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class StreamType>
|
||||||
|
void Generator<StreamType>::MakeTextDefine(Item & item, Var & var)
|
||||||
|
{
|
||||||
|
var.str.clear();
|
||||||
|
var.res = ConvertToBool(var.str);
|
||||||
|
var.is_function = false;
|
||||||
|
|
||||||
|
if( item.function.parameters.empty() )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( item.function.parameters.size() > 1 )
|
||||||
|
{
|
||||||
|
CreateMsg(L"[def] can have only one parameter");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Item::Function & fun = *item.function.parameters[0];
|
||||||
|
|
||||||
|
if( fun.is_function )
|
||||||
|
{
|
||||||
|
// call function
|
||||||
|
if( Call(fun, nullptr, stream_temp_define, true, empty_stream) )
|
||||||
|
{
|
||||||
|
#ifdef EZC_HAS_SPECIAL_STREAM
|
||||||
|
var.str += stream_temp_define.Str();
|
||||||
|
#else
|
||||||
|
var.str += stream_temp_define.str();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
var.res = last_res;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CreateMsg(L"[def] unknown function/block/variable", item.function.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var.str = fun.name;
|
||||||
|
var.res = ConvertToBool(fun.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template<class StreamType>
|
template<class StreamType>
|
||||||
void Generator<StreamType>::MakeTextDefine(Item & item)
|
void Generator<StreamType>::MakeTextDefine(Item & item)
|
||||||
{
|
{
|
||||||
if( !can_use_vars )
|
if( !can_use_vars || !pvars )
|
||||||
{
|
{
|
||||||
CreateMsg(L"[def] statement not available");
|
CreateMsg(L"[def] statement not available");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Var & var = vars[item.function.name];
|
Var & var = (*pvars)[item.function.name];
|
||||||
var.str.clear();
|
MakeTextDefine(item, var);
|
||||||
var.res = false;
|
}
|
||||||
|
|
||||||
for(size_t i=0 ; i < item.function.parameters.size() ; ++i)
|
|
||||||
{
|
|
||||||
if( !item.function.parameters[i]->is_function )
|
|
||||||
{
|
|
||||||
var.str += item.function.parameters[i]->name;
|
|
||||||
var.res = ConvertToBool(item.function.parameters[i]->name);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// it is a function parameter
|
|
||||||
if( Call(*item.function.parameters[i], stream_temp_define, true, empty_stream) )
|
|
||||||
{
|
|
||||||
#ifdef EZC_HAS_SPECIAL_STREAM
|
|
||||||
var.str += stream_temp_define.Str();
|
|
||||||
#else
|
|
||||||
var.str += stream_temp_define.str();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
var.res = last_res;
|
|
||||||
}
|
template<class StreamType>
|
||||||
else
|
void Generator<StreamType>::MakeTextDefineIfNotSet(Item & item)
|
||||||
{
|
{
|
||||||
CreateMsg(L"[def] unknown function/block/variable", item.function.name);
|
if( !can_use_vars || !pvars )
|
||||||
}
|
{
|
||||||
}
|
CreateMsg(L"[def?] statement not available");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vars::iterator vi = pvars->find(item.function.name);
|
||||||
|
|
||||||
|
if( vi == pvars->end() )
|
||||||
|
{
|
||||||
|
Var & var = (*pvars)[item.function.name];
|
||||||
|
MakeTextDefine(item, var);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template<class StreamType>
|
||||||
|
void Generator<StreamType>::MakeTextLet(Item & item, Var & var)
|
||||||
|
{
|
||||||
|
var.str.clear();
|
||||||
|
var.res = ConvertToBool(var.str);
|
||||||
|
var.is_function = true;
|
||||||
|
|
||||||
|
if( item.function.parameters.empty() )
|
||||||
|
{
|
||||||
|
var.is_function = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( item.function.parameters.size() > 1 )
|
||||||
|
{
|
||||||
|
CreateMsg(L"[let] can have only one parameter");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Item::Function & fun = *item.function.parameters[0];
|
||||||
|
var.str = fun.name;
|
||||||
|
var.is_function = fun.is_function;
|
||||||
|
|
||||||
|
if( !fun.is_function )
|
||||||
|
{
|
||||||
|
var.res = ConvertToBool(var.str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class StreamType>
|
||||||
|
void Generator<StreamType>::MakeTextLet(Item & item)
|
||||||
|
{
|
||||||
|
if( !can_use_vars || !pvars )
|
||||||
|
{
|
||||||
|
CreateMsg(L"[let] statement not available");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Var & var = (*pvars)[item.function.name];
|
||||||
|
MakeTextLet(item, var);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class StreamType>
|
||||||
|
void Generator<StreamType>::MakeTextLetIfNotSet(Item & item)
|
||||||
|
{
|
||||||
|
if( !can_use_vars || !pvars )
|
||||||
|
{
|
||||||
|
CreateMsg(L"[let?] statement not available");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vars::iterator vi = pvars->find(item.function.name);
|
||||||
|
|
||||||
|
if( vi == pvars->end() )
|
||||||
|
{
|
||||||
|
Var & var = (*pvars)[item.function.name];
|
||||||
|
MakeTextLet(item, var);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template<class StreamType>
|
template<class StreamType>
|
||||||
void Generator<StreamType>::MakeTextFilter(Item & item)
|
void Generator<StreamType>::MakeTextFilter(Item & item)
|
||||||
{
|
{
|
||||||
|
@ -1683,11 +1821,11 @@ void Generator<StreamType>::MakeTextFilter(Item & item)
|
||||||
|
|
||||||
if( old_stream )
|
if( old_stream )
|
||||||
{
|
{
|
||||||
Call(item.function, *old_stream, false, *output_stream);
|
Call(item.function, nullptr, *old_stream, false, *output_stream);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Call(item.function, stream_temp1, true, *output_stream);
|
Call(item.function, nullptr, stream_temp1, true, *output_stream);
|
||||||
ClearStream(stream_temp1);
|
ClearStream(stream_temp1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1777,12 +1915,14 @@ void Generator<StreamType>::MakeTextReturn(Item & item)
|
||||||
{
|
{
|
||||||
// output stream in [return] statement is ignored (we use only the stream produced by the whole block)
|
// output stream in [return] statement is ignored (we use only the stream produced by the whole block)
|
||||||
// this Call() sets last_res which is used later when we return to CallBlock()
|
// this Call() sets last_res which is used later when we return to CallBlock()
|
||||||
Call(item.function, stream_temp1, false, empty_stream);
|
Call(item.function, nullptr, stream_temp1, false, empty_stream);
|
||||||
ClearStream(stream_temp1);
|
ClearStream(stream_temp1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template<class StreamType>
|
template<class StreamType>
|
||||||
bool Generator<StreamType>::LimitAchieved()
|
bool Generator<StreamType>::LimitAchieved()
|
||||||
{
|
{
|
||||||
|
@ -1831,15 +1971,18 @@ void Generator<StreamType>::MakeText(Item & item)
|
||||||
stack_tab[stack_index-1].Clear();
|
stack_tab[stack_index-1].Clear();
|
||||||
stack_tab[stack_index-1].item = &item;
|
stack_tab[stack_index-1].item = &item;
|
||||||
|
|
||||||
if ( item.type == Item::item_text ) MakeItemText(item);
|
if ( item.type == Item::item_text ) MakeItemText(item);
|
||||||
else if( item.type == Item::item_container )MakeTextContainer(item);
|
else if( item.type == Item::item_container ) MakeTextContainer(item);
|
||||||
else if( item.type == Item::item_function ) MakeTextNormal(item);
|
else if( item.type == Item::item_function ) MakeTextNormal(item);
|
||||||
else if( item.type == Item::item_if ) MakeTextIf(item);
|
else if( item.type == Item::item_if ) MakeTextIf(item);
|
||||||
else if( item.type == Item::item_def ) MakeTextDefine(item);
|
else if( item.type == Item::item_def ) MakeTextDefine(item);
|
||||||
else if( item.type == Item::item_for ) MakeTextFor(item);
|
else if( item.type == Item::item_def_if_not_set ) MakeTextDefineIfNotSet(item);
|
||||||
else if( item.type == Item::item_filter ) MakeTextFilter(item);
|
else if( item.type == Item::item_let ) MakeTextLet(item);
|
||||||
else if( item.type == Item::item_ezc ) MakeTextEzc(item);
|
else if( item.type == Item::item_let_if_not_set ) MakeTextLetIfNotSet(item);
|
||||||
else if( item.type == Item::item_return ) MakeTextReturn(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 )
|
else if( item.type == Item::item_err )
|
||||||
CreateMsg(L"a wrong directive");
|
CreateMsg(L"a wrong directive");
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2007-2018, Tomasz Sowa
|
* Copyright (c) 2007-2021, Tomasz Sowa
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -55,7 +55,8 @@ struct Item
|
||||||
{
|
{
|
||||||
item_none, item_container, item_text, item_function, item_if,
|
item_none, item_container, item_text, item_function, item_if,
|
||||||
item_for, item_else, item_end, item_err, item_include, item_comment,
|
item_for, item_else, item_end, item_err, item_include, item_comment,
|
||||||
item_def, item_filter, item_ezc, item_block, item_return
|
item_def, item_def_if_not_set, item_let, item_let_if_not_set,
|
||||||
|
item_filter, item_ezc, item_block, item_return
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2007-2018, Tomasz Sowa
|
* Copyright (c) 2007-2021, Tomasz Sowa
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -486,7 +486,7 @@ bool PatternParser::IsNameChar(wchar_t c)
|
||||||
return ((c>='a' && c<='z') ||
|
return ((c>='a' && c<='z') ||
|
||||||
(c>='A' && c<='Z') ||
|
(c>='A' && c<='Z') ||
|
||||||
(c>='0' && c<='9') ||
|
(c>='0' && c<='9') ||
|
||||||
c=='_' || c=='-' || c=='.' || c=='#');
|
c=='_' || c=='-' || c=='.' || c=='#' || c=='?');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -784,10 +784,85 @@ void PatternParser::ReadDirectiveInclude(Item & item)
|
||||||
void PatternParser::ReadDirectiveDef(Item & item)
|
void PatternParser::ReadDirectiveDef(Item & item)
|
||||||
{
|
{
|
||||||
item.type = Item::item_def;
|
item.type = Item::item_def;
|
||||||
ReadFunction(item);
|
|
||||||
|
if( ReadFunction(item) )
|
||||||
|
{
|
||||||
|
if( item.function.parameters.size() > 1 )
|
||||||
|
item.type = Item::item_err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PatternParser::ReadDirectiveDefIfNotSet(Item & item)
|
||||||
|
{
|
||||||
|
item.type = Item::item_def_if_not_set;
|
||||||
|
|
||||||
|
if( ReadFunction(item) )
|
||||||
|
{
|
||||||
|
if( item.function.parameters.size() > 1 )
|
||||||
|
item.type = Item::item_err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PatternParser::ReadDirectiveLet(Item & item)
|
||||||
|
{
|
||||||
|
item.type = Item::item_let;
|
||||||
|
|
||||||
|
if( ReadFunction(item) )
|
||||||
|
{
|
||||||
|
std::vector<Item::Function*> & parameters = item.function.parameters;
|
||||||
|
|
||||||
|
if( parameters.size() > 1 )
|
||||||
|
{
|
||||||
|
item.type = Item::item_err;
|
||||||
|
item.function.Clear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if( parameters.size() == 1 && parameters[0]->is_function && !parameters[0]->parameters.empty() )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* if the first parameter in [let] is a function e.g. [let variable function_name] (here the first parameter is function_name)
|
||||||
|
* then the function cannot have parameters itselt (because it is not evaluated here)
|
||||||
|
* this is only an alias
|
||||||
|
*/
|
||||||
|
item.type = Item::item_err;
|
||||||
|
item.function.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PatternParser::ReadDirectiveLetIfNotSet(Item & item)
|
||||||
|
{
|
||||||
|
item.type = Item::item_let_if_not_set;
|
||||||
|
|
||||||
|
if( ReadFunction(item) )
|
||||||
|
{
|
||||||
|
std::vector<Item::Function*> & parameters = item.function.parameters;
|
||||||
|
|
||||||
|
if( parameters.size() > 1 )
|
||||||
|
{
|
||||||
|
item.type = Item::item_err;
|
||||||
|
item.function.Clear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if( parameters.size() == 1 && parameters[0]->is_function && !parameters[0]->parameters.empty() )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* if the first parameter in [let] is a function e.g. [let variable function_name] (here the first parameter is function_name)
|
||||||
|
* then the function cannot have parameters itselt (because it is not evaluated here)
|
||||||
|
* this is only an alias
|
||||||
|
*/
|
||||||
|
item.type = Item::item_err;
|
||||||
|
item.function.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void PatternParser::ReadDirectiveFilter(Item & item)
|
void PatternParser::ReadDirectiveFilter(Item & item)
|
||||||
{
|
{
|
||||||
item.type = Item::item_filter;
|
item.type = Item::item_filter;
|
||||||
|
@ -825,11 +900,16 @@ void PatternParser::ReadDirectiveOut(Item & item)
|
||||||
void PatternParser::ReadDirectiveBlock(Item & item)
|
void PatternParser::ReadDirectiveBlock(Item & item)
|
||||||
{
|
{
|
||||||
item.type = Item::item_block;
|
item.type = Item::item_block;
|
||||||
ReadFunction(item);
|
|
||||||
|
|
||||||
// only one function without arguments
|
if( ReadFunction(item) )
|
||||||
if( !item.function.parameters.empty() )
|
{
|
||||||
item.type = Item::item_err;
|
// only one function without arguments
|
||||||
|
if( !item.function.parameters.empty() )
|
||||||
|
{
|
||||||
|
item.type = Item::item_err;
|
||||||
|
item.function.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -859,6 +939,9 @@ std::wstring name;
|
||||||
else if( name == L"for" ) ReadDirectiveFor(item);
|
else if( name == L"for" ) ReadDirectiveFor(item);
|
||||||
else if( name == L"include" ) ReadDirectiveInclude(item);
|
else if( name == L"include" ) ReadDirectiveInclude(item);
|
||||||
else if( name == L"def" ) ReadDirectiveDef(item);
|
else if( name == L"def" ) ReadDirectiveDef(item);
|
||||||
|
else if( name == L"def?" ) ReadDirectiveDefIfNotSet(item);
|
||||||
|
else if( name == L"let" ) ReadDirectiveLet(item);
|
||||||
|
else if( name == L"let?" ) ReadDirectiveLetIfNotSet(item);
|
||||||
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"out" ) ReadDirectiveOut(item);
|
else if( name == L"out" ) ReadDirectiveOut(item);
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2007-2018, Tomasz Sowa
|
* Copyright (c) 2007-2021, Tomasz Sowa
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -175,6 +175,9 @@ private:
|
||||||
void ReadDirectiveComment(Item & item);
|
void ReadDirectiveComment(Item & item);
|
||||||
void ReadDirectiveInclude(Item & item);
|
void ReadDirectiveInclude(Item & item);
|
||||||
void ReadDirectiveDef(Item & item);
|
void ReadDirectiveDef(Item & item);
|
||||||
|
void ReadDirectiveDefIfNotSet(Item & item);
|
||||||
|
void ReadDirectiveLet(Item & item);
|
||||||
|
void ReadDirectiveLetIfNotSet(Item & item);
|
||||||
void ReadDirectiveFilter(Item & item);
|
void ReadDirectiveFilter(Item & item);
|
||||||
void ReadDirectiveEzc(Item & item);
|
void ReadDirectiveEzc(Item & item);
|
||||||
void ReadDirectiveOut(Item & item);
|
void ReadDirectiveOut(Item & item);
|
||||||
|
|
Loading…
Reference in New Issue