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:
2021-05-23 10:02:51 +02:00
parent 6f6df9524c
commit 0ac8e05c04
6 changed files with 356 additions and 109 deletions

View File

@@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2007-2018, Tomasz Sowa
* Copyright (c) 2007-2021, Tomasz Sowa
* All rights reserved.
*
* 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') ||
(c>='A' && c<='Z') ||
(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)
{
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)
{
item.type = Item::item_filter;
@@ -825,11 +900,16 @@ void PatternParser::ReadDirectiveOut(Item & item)
void PatternParser::ReadDirectiveBlock(Item & item)
{
item.type = Item::item_block;
ReadFunction(item);
// only one function without arguments
if( !item.function.parameters.empty() )
item.type = Item::item_err;
if( ReadFunction(item) )
{
// 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"include" ) ReadDirectiveInclude(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"ezc" ) ReadDirectiveEzc(item);
else if( name == L"out" ) ReadDirectiveOut(item);