Macroprocessor: replace naked pointers by smart pointers
- use std::unique_ptr for MacroDriver::lexer - use std::shared_ptr for MacroValue objects constructed by the parser This is made possible using Bison 3.0 variant value type. Using non-pointer type is not possible since MacroValue is polymorphic. Using std::unique_ptr is not possible since the value type must be copyable (see https://lists.gnu.org/archive/html/bug-bison/2015-03/msg00004.html). Define a new type MacroValuePtr == shared_ptr<const MacroValue> for code clarity. Use the following convention for shared_ptr arguments to functions: + if pass-by-value, means that the callee acquires ownership + if pass-by-const-reference, the callee does not acquire ownership - naked pointers are still used for tracking the filename in Bison's location type, since we don't have control over that Also, by the way: - arrays can now contain elements of any type - simplify MacroDriver::loop_stack using std::tuple - toArray() method now fails on function objects - no need to use const qualifiers, since all MacroValue objects are immutable - use an exception for detecting division by zeroissue#70
parent
372005ed27
commit
5f1465f9d1
|
@ -18,8 +18,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
%language "c++"
|
%language "c++"
|
||||||
%require "2.5"
|
%require "3.0"
|
||||||
%defines
|
%defines
|
||||||
|
%define api.value.type variant
|
||||||
|
%define parse.assert
|
||||||
|
|
||||||
%code top {
|
%code top {
|
||||||
class MacroDriver;
|
class MacroDriver;
|
||||||
|
@ -45,14 +47,6 @@ class MacroDriver;
|
||||||
#include "MacroValue.hh"
|
#include "MacroValue.hh"
|
||||||
}
|
}
|
||||||
|
|
||||||
%union
|
|
||||||
{
|
|
||||||
string *string_val;
|
|
||||||
int int_val;
|
|
||||||
const MacroValue *mv;
|
|
||||||
vector<string> *vector_string_val;
|
|
||||||
};
|
|
||||||
|
|
||||||
%code {
|
%code {
|
||||||
#include "MacroDriver.hh"
|
#include "MacroDriver.hh"
|
||||||
|
|
||||||
|
@ -76,8 +70,8 @@ class MacroDriver;
|
||||||
%token DEFINE LINE FOR IN IF ELSE ENDIF ECHO_DIR ERROR IFDEF IFNDEF
|
%token DEFINE LINE FOR IN IF ELSE ENDIF ECHO_DIR ERROR IFDEF IFNDEF
|
||||||
%token LPAREN RPAREN LBRACKET RBRACKET EQUAL EOL LENGTH ECHOMACROVARS SAVE
|
%token LPAREN RPAREN LBRACKET RBRACKET EQUAL EOL LENGTH ECHOMACROVARS SAVE
|
||||||
|
|
||||||
%token <int_val> INTEGER
|
%token <int> INTEGER
|
||||||
%token <string_val> NAME STRING
|
%token <string> NAME STRING
|
||||||
|
|
||||||
%left COMMA
|
%left COMMA
|
||||||
%left LOGICAL_OR
|
%left LOGICAL_OR
|
||||||
|
@ -90,8 +84,9 @@ class MacroDriver;
|
||||||
%left UMINUS UPLUS EXCLAMATION
|
%left UMINUS UPLUS EXCLAMATION
|
||||||
%left LBRACKET
|
%left LBRACKET
|
||||||
|
|
||||||
%type <vector_string_val> func_args
|
%type <vector<string>> func_args
|
||||||
%type <mv> expr array_expr
|
%type <MacroValuePtr> expr
|
||||||
|
%type <vector<MacroValuePtr>> comma_expr
|
||||||
%%
|
%%
|
||||||
|
|
||||||
%start statement_list_or_nothing;
|
%start statement_list_or_nothing;
|
||||||
|
@ -107,15 +102,15 @@ statement_list : statement EOL
|
||||||
statement : expr
|
statement : expr
|
||||||
{ out << $1->toString(); }
|
{ out << $1->toString(); }
|
||||||
| DEFINE NAME EQUAL expr
|
| DEFINE NAME EQUAL expr
|
||||||
{ driver.set_variable(*$2, $4); delete $2; }
|
{ driver.set_variable($2, $4); }
|
||||||
| FOR NAME IN expr
|
| FOR NAME IN expr
|
||||||
{ TYPERR_CATCH(driver.init_loop(*$2, $4), @$); delete $2; }
|
{ TYPERR_CATCH(driver.init_loop($2, $4), @$); }
|
||||||
| IF expr
|
| IF expr
|
||||||
{ TYPERR_CATCH(driver.begin_if($2), @$); }
|
{ TYPERR_CATCH(driver.begin_if($2), @$); }
|
||||||
| IFDEF NAME
|
| IFDEF NAME
|
||||||
{ TYPERR_CATCH(driver.begin_ifdef(*$2), @$); delete $2; }
|
{ TYPERR_CATCH(driver.begin_ifdef($2), @$); }
|
||||||
| IFNDEF NAME
|
| IFNDEF NAME
|
||||||
{ TYPERR_CATCH(driver.begin_ifndef(*$2), @$); delete $2; }
|
{ TYPERR_CATCH(driver.begin_ifndef($2), @$); }
|
||||||
| ECHO_DIR expr
|
| ECHO_DIR expr
|
||||||
{ TYPERR_CATCH(driver.echo(@$, $2), @$); }
|
{ TYPERR_CATCH(driver.echo(@$, $2), @$); }
|
||||||
| ERROR expr
|
| ERROR expr
|
||||||
|
@ -126,98 +121,96 @@ statement : expr
|
||||||
{ driver.printvars(@$, true); }
|
{ driver.printvars(@$, true); }
|
||||||
| ECHOMACROVARS LPAREN SAVE RPAREN
|
| ECHOMACROVARS LPAREN SAVE RPAREN
|
||||||
{ out << driver.printvars(@$, false); }
|
{ out << driver.printvars(@$, false); }
|
||||||
| DEFINE NAME LPAREN func_args { driver.push_args_into_func_env(*$4); } RPAREN EQUAL expr
|
| DEFINE NAME LPAREN func_args { driver.push_args_into_func_env($4); } RPAREN EQUAL expr
|
||||||
{
|
{
|
||||||
TYPERR_CATCH(driver.set_string_function(*$2, *$4, $8), @$);
|
TYPERR_CATCH(driver.set_string_function($2, $4, $8), @$);
|
||||||
driver.pop_func_env();
|
driver.pop_func_env();
|
||||||
delete $2;
|
|
||||||
delete $4;
|
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
func_args : NAME
|
func_args : NAME
|
||||||
{ $$ = new vector<string>(); $$->push_back(*$1); delete $1; }
|
{ $$ = vector<string>{$1}; }
|
||||||
| func_args COMMA NAME
|
| func_args COMMA NAME
|
||||||
{ $$->push_back(*$3); delete $3; }
|
{ $1.push_back($3); $$ = $1; }
|
||||||
;
|
;
|
||||||
|
|
||||||
expr : INTEGER
|
expr : INTEGER
|
||||||
{ $$ = new IntMV(driver, $1); }
|
{ $$ = make_shared<IntMV>($1); }
|
||||||
| STRING
|
| STRING
|
||||||
{ $$ = new StringMV(driver, driver.replace_vars_in_str(*$1)); delete $1; }
|
{ $$ = make_shared<StringMV>(driver.replace_vars_in_str($1)); }
|
||||||
| NAME
|
| NAME
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
$$ = driver.get_variable(*$1);
|
$$ = driver.get_variable($1);
|
||||||
}
|
}
|
||||||
catch(MacroDriver::UnknownVariable(&e))
|
catch(MacroDriver::UnknownVariable(&e))
|
||||||
{
|
{
|
||||||
error(@$, "Unknown variable: " + e.name);
|
error(@$, "Unknown variable: " + e.name);
|
||||||
}
|
}
|
||||||
delete $1;
|
|
||||||
}
|
}
|
||||||
| NAME LPAREN array_expr RPAREN
|
| NAME LPAREN comma_expr RPAREN
|
||||||
{ TYPERR_CATCH($$ = driver.eval_string_function(*$1, $3), @$); delete $1; }
|
{ TYPERR_CATCH($$ = driver.eval_string_function($1, $3), @$); }
|
||||||
| LENGTH LPAREN expr RPAREN
|
| LENGTH LPAREN expr RPAREN
|
||||||
{ TYPERR_CATCH($$ = $3->length(), @$); }
|
{ TYPERR_CATCH($$ = $3->length(), @$); }
|
||||||
| LPAREN expr RPAREN
|
| LPAREN expr RPAREN
|
||||||
{ $$ = $2; }
|
{ $$ = $2; }
|
||||||
| expr PLUS expr
|
| expr PLUS expr
|
||||||
{ TYPERR_CATCH($$ = *$1 + *$3, @$); }
|
{ TYPERR_CATCH($$ = $1->plus($3), @$); }
|
||||||
| expr MINUS expr
|
| expr MINUS expr
|
||||||
{ TYPERR_CATCH($$ = *$1 - *$3, @$); }
|
{ TYPERR_CATCH($$ = $1->minus($3), @$); }
|
||||||
| expr TIMES expr
|
| expr TIMES expr
|
||||||
{ TYPERR_CATCH($$ = *$1 * *$3, @$); }
|
{ TYPERR_CATCH($$ = $1->times($3), @$); }
|
||||||
| expr DIVIDE expr
|
| expr DIVIDE expr
|
||||||
{
|
{
|
||||||
if (dynamic_cast<const IntMV *>($3) != NULL
|
TYPERR_CATCH($$ = $1->divide($3), @$)
|
||||||
&& ((IntMV *)$3)->get_int_value() == 0)
|
catch(MacroValue::DivisionByZeroError)
|
||||||
driver.error(@$, "Division by zero");
|
{
|
||||||
TYPERR_CATCH($$ = *$1 / *$3, @$);
|
error(@$, "Division by zero");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
| expr LESS expr
|
| expr LESS expr
|
||||||
{ TYPERR_CATCH($$ = *$1 < *$3, @$); }
|
{ TYPERR_CATCH($$ = $1->is_less($3), @$); }
|
||||||
| expr GREATER expr
|
| expr GREATER expr
|
||||||
{ TYPERR_CATCH($$ = *$1 > *$3, @$); }
|
{ TYPERR_CATCH($$ = $1->is_greater($3), @$); }
|
||||||
| expr LESS_EQUAL expr
|
| expr LESS_EQUAL expr
|
||||||
{ TYPERR_CATCH($$ = *$1 <= *$3, @$); }
|
{ TYPERR_CATCH($$ = $1->is_less_equal($3), @$); }
|
||||||
| expr GREATER_EQUAL expr
|
| expr GREATER_EQUAL expr
|
||||||
{ TYPERR_CATCH($$ = *$1 >= *$3, @$); }
|
{ TYPERR_CATCH($$ = $1->is_greater_equal($3), @$); }
|
||||||
| expr EQUAL_EQUAL expr
|
| expr EQUAL_EQUAL expr
|
||||||
{ TYPERR_CATCH($$ = *$1 == *$3, @$); }
|
{ $$ = $1->is_equal($3); }
|
||||||
| expr EXCLAMATION_EQUAL expr
|
| expr EXCLAMATION_EQUAL expr
|
||||||
{ TYPERR_CATCH($$ = *$1 != *$3, @$); }
|
{ $$ = $1->is_different($3); }
|
||||||
| expr LOGICAL_OR expr
|
| expr LOGICAL_OR expr
|
||||||
{ TYPERR_CATCH($$ = *$1 || *$3, @$); }
|
{ TYPERR_CATCH($$ = $1->logical_or($3), @$); }
|
||||||
| expr LOGICAL_AND expr
|
| expr LOGICAL_AND expr
|
||||||
{ TYPERR_CATCH($$ = *$1 && *$3, @$); }
|
{ TYPERR_CATCH($$ = $1->logical_and($3), @$); }
|
||||||
| MINUS expr %prec UMINUS
|
| MINUS expr %prec UMINUS
|
||||||
{ TYPERR_CATCH($$ = -*$2, @$); }
|
{ TYPERR_CATCH($$ = $2->unary_minus(), @$); }
|
||||||
| PLUS expr %prec UPLUS
|
| PLUS expr %prec UPLUS
|
||||||
{ TYPERR_CATCH($$ = +(*$2), @$); }
|
{ TYPERR_CATCH($$ = $2->unary_plus(), @$); }
|
||||||
| EXCLAMATION expr
|
| EXCLAMATION expr
|
||||||
{ TYPERR_CATCH($$ = !*$2, @$); }
|
{ TYPERR_CATCH($$ = $2->logical_not(), @$); }
|
||||||
| expr LBRACKET array_expr RBRACKET
|
| expr LBRACKET expr RBRACKET
|
||||||
{
|
{
|
||||||
TYPERR_CATCH($$ = (*$1)[*$3], @$)
|
TYPERR_CATCH($$ = $1->subscript($3), @$)
|
||||||
catch(MacroValue::OutOfBoundsError)
|
catch(MacroValue::OutOfBoundsError)
|
||||||
{
|
{
|
||||||
error(@$, "Index out of bounds");
|
error(@$, "Index out of bounds");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
| LBRACKET array_expr RBRACKET
|
| LBRACKET comma_expr RBRACKET
|
||||||
{ $$ = $2; }
|
{ $$ = make_shared<ArrayMV>($2); }
|
||||||
| expr COLON expr
|
| expr COLON expr
|
||||||
{ TYPERR_CATCH($$ = IntMV::new_range(driver, $1, $3), @$); }
|
{ TYPERR_CATCH($$ = ArrayMV::range($1, $3), @$); }
|
||||||
| expr IN expr
|
| expr IN expr
|
||||||
{ TYPERR_CATCH($$ = $1->in($3), @$); }
|
{ TYPERR_CATCH($$ = $3->in($1), @$); }
|
||||||
;
|
;
|
||||||
|
|
||||||
array_expr : expr
|
comma_expr : expr
|
||||||
{ $$ = $1->toArray(); }
|
{ $$ = vector<MacroValuePtr>{$1}; }
|
||||||
| array_expr COMMA expr
|
| comma_expr COMMA expr
|
||||||
{ TYPERR_CATCH($$ = $3->append($1), @$); }
|
{ $1.push_back($3); $$ = $1; }
|
||||||
;
|
;
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
|
@ -26,15 +26,6 @@
|
||||||
|
|
||||||
#include "MacroDriver.hh"
|
#include "MacroDriver.hh"
|
||||||
|
|
||||||
MacroDriver::MacroDriver()
|
|
||||||
= default;
|
|
||||||
|
|
||||||
MacroDriver::~MacroDriver()
|
|
||||||
{
|
|
||||||
for (auto value : values)
|
|
||||||
delete value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
MacroDriver::parse(const string &f, const string &fb, const string &modfiletxt,
|
MacroDriver::parse(const string &f, const string &fb, const string &modfiletxt,
|
||||||
ostream &out, bool debug, bool no_line_macro_arg, map<string, string> defines,
|
ostream &out, bool debug, bool no_line_macro_arg, map<string, string> defines,
|
||||||
|
@ -66,7 +57,7 @@ MacroDriver::parse(const string &f, const string &fb, const string &modfiletxt,
|
||||||
}
|
}
|
||||||
file_with_endl << modfiletxt << endl;
|
file_with_endl << modfiletxt << endl;
|
||||||
|
|
||||||
lexer = new MacroFlex(&file_with_endl, &out, no_line_macro, path);
|
lexer = make_unique<MacroFlex>(&file_with_endl, &out, no_line_macro, path);
|
||||||
lexer->set_debug(debug);
|
lexer->set_debug(debug);
|
||||||
|
|
||||||
Macro::parser parser(*this, out);
|
Macro::parser parser(*this, out);
|
||||||
|
@ -78,8 +69,6 @@ MacroDriver::parse(const string &f, const string &fb, const string &modfiletxt,
|
||||||
|
|
||||||
// Launch macro-processing
|
// Launch macro-processing
|
||||||
parser.parse();
|
parser.parse();
|
||||||
|
|
||||||
delete lexer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -93,7 +82,7 @@ string
|
||||||
MacroDriver::replace_vars_in_str(const string &s) const
|
MacroDriver::replace_vars_in_str(const string &s) const
|
||||||
{
|
{
|
||||||
if (s.find("@") == string::npos)
|
if (s.find("@") == string::npos)
|
||||||
return string(s);
|
return s;
|
||||||
|
|
||||||
string retval(s);
|
string retval(s);
|
||||||
smatch name;
|
smatch name;
|
||||||
|
@ -107,7 +96,7 @@ MacroDriver::replace_vars_in_str(const string &s) const
|
||||||
regex_search(macro, name, name_regex);
|
regex_search(macro, name, name_regex);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
const MacroValue *mv = nullptr;
|
MacroValuePtr mv;
|
||||||
bool found_in_func_env = false;
|
bool found_in_func_env = false;
|
||||||
for (unsigned i = func_env.size(); i-- > 0;)
|
for (unsigned i = func_env.size(); i-- > 0;)
|
||||||
{
|
{
|
||||||
|
@ -122,7 +111,7 @@ MacroDriver::replace_vars_in_str(const string &s) const
|
||||||
if (!found_in_func_env)
|
if (!found_in_func_env)
|
||||||
mv = get_variable(name.str());
|
mv = get_variable(name.str());
|
||||||
|
|
||||||
if (mv != nullptr)
|
if (mv)
|
||||||
{
|
{
|
||||||
// mv will equal nullptr if we have
|
// mv will equal nullptr if we have
|
||||||
// @#define y = 1
|
// @#define y = 1
|
||||||
|
@ -141,28 +130,27 @@ MacroDriver::replace_vars_in_str(const string &s) const
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MacroDriver::set_string_function(const string &name, vector<string> &args, const MacroValue *value)
|
MacroDriver::set_string_function(const string &name, vector<string> &args, const MacroValuePtr &value)
|
||||||
{
|
{
|
||||||
auto *smv = dynamic_cast<const StringMV *>(value);
|
auto smv = dynamic_pointer_cast<StringMV>(value);
|
||||||
if (!smv)
|
if (!smv)
|
||||||
throw MacroValue::TypeError("The definition of a macro function must evaluate to a string");
|
throw MacroValue::TypeError("The definition of a macro function must evaluate to a string");
|
||||||
|
|
||||||
env[name] = new FuncMV(*this, args, *(const_cast<StringMV *>(smv)));
|
env[name] = make_shared<FuncMV>(args, smv->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
const StringMV *
|
MacroValuePtr
|
||||||
MacroDriver::eval_string_function(const string &name, const MacroValue *args)
|
MacroDriver::eval_string_function(const string &name, const vector<MacroValuePtr> &args)
|
||||||
{
|
{
|
||||||
auto it = env.find(name);
|
auto it = env.find(name);
|
||||||
if (it == env.end())
|
if (it == env.end())
|
||||||
throw UnknownVariable(name);
|
throw UnknownVariable(name);
|
||||||
|
|
||||||
const auto *fmv = dynamic_cast<const FuncMV *>(env[name]);
|
auto fmv = dynamic_pointer_cast<FuncMV>(it->second);
|
||||||
if (!fmv)
|
if (!fmv)
|
||||||
throw MacroValue::TypeError("You are using " + name + " as if it were a macro function");
|
throw MacroValue::TypeError("You are using " + name + " as if it were a macro function");
|
||||||
|
|
||||||
vector<string> func_args = fmv->get_args();
|
if (fmv->args.size() != args.size())
|
||||||
if (func_args.size() != (size_t)dynamic_cast<const IntMV *>(args->length())->get_int_value())
|
|
||||||
{
|
{
|
||||||
cerr << "Macroprocessor: The evaluation of: " << name << " could not be completed" << endl
|
cerr << "Macroprocessor: The evaluation of: " << name << " could not be completed" << endl
|
||||||
<< "because the number of arguments provided is different than the number of" << endl
|
<< "because the number of arguments provided is different than the number of" << endl
|
||||||
|
@ -172,11 +160,11 @@ MacroDriver::eval_string_function(const string &name, const MacroValue *args)
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
env_t func_env_map;
|
env_t func_env_map;
|
||||||
for (const auto it : func_args)
|
for (const auto it : fmv->args)
|
||||||
func_env_map[it] = args->at(i++);
|
func_env_map[it] = args[i++];
|
||||||
|
|
||||||
func_env.push_back(func_env_map);
|
func_env.push_back(func_env_map);
|
||||||
StringMV *smv = new StringMV(*this, replace_vars_in_str(fmv->toString()));
|
auto smv = make_shared<StringMV>(replace_vars_in_str(fmv->toString()));
|
||||||
pop_func_env();
|
pop_func_env();
|
||||||
return smv;
|
return smv;
|
||||||
}
|
}
|
||||||
|
@ -186,7 +174,7 @@ MacroDriver::push_args_into_func_env(const vector<string> &args)
|
||||||
{
|
{
|
||||||
env_t func_env_map;
|
env_t func_env_map;
|
||||||
for (const auto it : args)
|
for (const auto it : args)
|
||||||
func_env_map[it] = NULL;
|
func_env_map[it] = MacroValuePtr();
|
||||||
func_env.push_back(func_env_map);
|
func_env.push_back(func_env_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,12 +185,12 @@ MacroDriver::pop_func_env()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MacroDriver::set_variable(const string &name, const MacroValue *value)
|
MacroDriver::set_variable(const string &name, MacroValuePtr value)
|
||||||
{
|
{
|
||||||
env[name] = value;
|
env[name] = move(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
const MacroValue *
|
MacroValuePtr
|
||||||
MacroDriver::get_variable(const string &name) const noexcept(false)
|
MacroDriver::get_variable(const string &name) const noexcept(false)
|
||||||
{
|
{
|
||||||
auto it = env.find(name);
|
auto it = env.find(name);
|
||||||
|
@ -212,13 +200,12 @@ MacroDriver::get_variable(const string &name) const noexcept(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MacroDriver::init_loop(const string &name, const MacroValue *value) noexcept(false)
|
MacroDriver::init_loop(const string &name, MacroValuePtr value) noexcept(false)
|
||||||
{
|
{
|
||||||
const auto *mv1 = dynamic_cast<const ArrayMV<int> *>(value);
|
auto mv = dynamic_pointer_cast<ArrayMV>(value);
|
||||||
const auto *mv2 = dynamic_cast<const ArrayMV<string> *>(value);
|
if (!mv)
|
||||||
if (!mv1 && !mv2)
|
|
||||||
throw MacroValue::TypeError("Argument of @#for loop must be an array expression");
|
throw MacroValue::TypeError("Argument of @#for loop must be an array expression");
|
||||||
loop_stack.emplace(name, make_pair(value, 0));
|
loop_stack.emplace(name, move(mv), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -227,44 +214,26 @@ MacroDriver::iter_loop()
|
||||||
if (loop_stack.empty())
|
if (loop_stack.empty())
|
||||||
throw "No loop on which to iterate!";
|
throw "No loop on which to iterate!";
|
||||||
|
|
||||||
int &i = loop_stack.top().second.second;
|
int &i = get<2>(loop_stack.top());
|
||||||
const MacroValue *mv = loop_stack.top().second.first;
|
auto mv = get<1>(loop_stack.top());
|
||||||
string name = loop_stack.top().first;
|
string &name = get<0>(loop_stack.top());
|
||||||
|
|
||||||
const auto *mv1 = dynamic_cast<const ArrayMV<int> *>(mv);
|
if (i >= static_cast<int>(mv->values.size()))
|
||||||
if (mv1)
|
|
||||||
{
|
|
||||||
if (i >= (int) mv1->values.size())
|
|
||||||
{
|
{
|
||||||
loop_stack.pop();
|
loop_stack.pop();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
env[name] = new IntMV(*this, mv1->values[i++]);
|
env[name] = mv->values[i++];
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const auto *mv2 = dynamic_cast<const ArrayMV<string> *>(mv);
|
|
||||||
if (i >= (int) mv2->values.size())
|
|
||||||
{
|
|
||||||
loop_stack.pop();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
env[name] = new StringMV(*this, mv2->values[i++]);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MacroDriver::begin_if(const MacroValue *value) noexcept(false)
|
MacroDriver::begin_if(const MacroValuePtr &value) noexcept(false)
|
||||||
{
|
{
|
||||||
const auto *ival = dynamic_cast<const IntMV *>(value);
|
auto ival = dynamic_pointer_cast<IntMV>(value);
|
||||||
if (!ival)
|
if (!ival)
|
||||||
throw MacroValue::TypeError("Argument of @#if must be an integer");
|
throw MacroValue::TypeError("Argument of @#if must be an integer");
|
||||||
last_if = (bool) ival->value;
|
last_if = (bool) ival->value;
|
||||||
|
@ -276,11 +245,11 @@ MacroDriver::begin_ifdef(const string &name)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
get_variable(name);
|
get_variable(name);
|
||||||
begin_if(new IntMV(*this, 1));
|
begin_if(make_shared<IntMV>(1));
|
||||||
}
|
}
|
||||||
catch (UnknownVariable &)
|
catch (UnknownVariable &)
|
||||||
{
|
{
|
||||||
begin_if(new IntMV(*this, 0));
|
begin_if(make_shared<IntMV>(0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,18 +259,18 @@ MacroDriver::begin_ifndef(const string &name)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
get_variable(name);
|
get_variable(name);
|
||||||
begin_if(new IntMV(*this, 0));
|
begin_if(make_shared<IntMV>(0));
|
||||||
}
|
}
|
||||||
catch (UnknownVariable &)
|
catch (UnknownVariable &)
|
||||||
{
|
{
|
||||||
begin_if(new IntMV(*this, 1));
|
begin_if(make_shared<IntMV>(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MacroDriver::echo(const Macro::parser::location_type &l, const MacroValue *value) const noexcept(false)
|
MacroDriver::echo(const Macro::parser::location_type &l, const MacroValuePtr &value) const noexcept(false)
|
||||||
{
|
{
|
||||||
const auto *sval = dynamic_cast<const StringMV *>(value);
|
auto sval = dynamic_pointer_cast<StringMV>(value);
|
||||||
if (!sval)
|
if (!sval)
|
||||||
throw MacroValue::TypeError("Argument of @#echo must be a string");
|
throw MacroValue::TypeError("Argument of @#echo must be a string");
|
||||||
|
|
||||||
|
@ -309,9 +278,9 @@ MacroDriver::echo(const Macro::parser::location_type &l, const MacroValue *value
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MacroDriver::error(const Macro::parser::location_type &l, const MacroValue *value) const noexcept(false)
|
MacroDriver::error(const Macro::parser::location_type &l, const MacroValuePtr &value) const noexcept(false)
|
||||||
{
|
{
|
||||||
const auto *sval = dynamic_cast<const StringMV *>(value);
|
auto sval = dynamic_pointer_cast<StringMV>(value);
|
||||||
if (!sval)
|
if (!sval)
|
||||||
throw MacroValue::TypeError("Argument of @#error must be a string");
|
throw MacroValue::TypeError("Argument of @#error must be a string");
|
||||||
|
|
||||||
|
@ -328,7 +297,7 @@ MacroDriver::printvars(const Macro::parser::location_type &l, const bool tostdou
|
||||||
for (const auto & it : env)
|
for (const auto & it : env)
|
||||||
{
|
{
|
||||||
cout << " ";
|
cout << " ";
|
||||||
const auto *fmv = dynamic_cast<const FuncMV *>(it.second);
|
auto fmv = dynamic_pointer_cast<FuncMV>(it.second);
|
||||||
if (!fmv)
|
if (!fmv)
|
||||||
cout << it.first << " = " << it.second->print() << endl;
|
cout << it.first << " = " << it.second->print() << endl;
|
||||||
else
|
else
|
||||||
|
|
|
@ -155,11 +155,8 @@ class MacroDriver
|
||||||
{
|
{
|
||||||
friend class MacroValue;
|
friend class MacroValue;
|
||||||
private:
|
private:
|
||||||
//! Stores all created macro values
|
|
||||||
set<const MacroValue *> values;
|
|
||||||
|
|
||||||
// The map defining an environment
|
// The map defining an environment
|
||||||
using env_t = map<string, const MacroValue *>;
|
using env_t = map<string, MacroValuePtr>;
|
||||||
|
|
||||||
//! Environment: maps macro variables to their values
|
//! Environment: maps macro variables to their values
|
||||||
env_t env;
|
env_t env;
|
||||||
|
@ -169,7 +166,7 @@ private:
|
||||||
|
|
||||||
//! Stack used to keep track of (possibly nested) loops
|
//! Stack used to keep track of (possibly nested) loops
|
||||||
//! First element is loop variable name, second is the array over which iteration is done, and third is subscript to be used by next call of iter_loop() (beginning with 0) */
|
//! First element is loop variable name, second is the array over which iteration is done, and third is subscript to be used by next call of iter_loop() (beginning with 0) */
|
||||||
stack<pair<string, pair<const MacroValue *, int>>> loop_stack;
|
stack<tuple<string, shared_ptr<ArrayMV>, int>> loop_stack;
|
||||||
public:
|
public:
|
||||||
//! Exception thrown when value of an unknown variable is requested
|
//! Exception thrown when value of an unknown variable is requested
|
||||||
class UnknownVariable
|
class UnknownVariable
|
||||||
|
@ -181,12 +178,6 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Constructor
|
|
||||||
MacroDriver();
|
|
||||||
//! Destructor
|
|
||||||
virtual
|
|
||||||
~MacroDriver();
|
|
||||||
|
|
||||||
//! Starts parsing a file, returns output in out
|
//! Starts parsing a file, returns output in out
|
||||||
/*! \param no_line_macro should we omit the @#line statements ? */
|
/*! \param no_line_macro should we omit the @#line statements ? */
|
||||||
void parse(const string &f, const string &fb, const string &modfiletxt, ostream &out, bool debug, bool no_line_macro_arg,
|
void parse(const string &f, const string &fb, const string &modfiletxt, ostream &out, bool debug, bool no_line_macro_arg,
|
||||||
|
@ -202,7 +193,7 @@ public:
|
||||||
bool no_line_macro;
|
bool no_line_macro;
|
||||||
|
|
||||||
//! Reference to the lexer
|
//! Reference to the lexer
|
||||||
class MacroFlex *lexer;
|
unique_ptr<MacroFlex> lexer;
|
||||||
|
|
||||||
//! Used to store the value of the last @#if condition
|
//! Used to store the value of the last @#if condition
|
||||||
bool last_if;
|
bool last_if;
|
||||||
|
@ -214,14 +205,14 @@ public:
|
||||||
string printvars(const Macro::parser::location_type &l, const bool save) const;
|
string printvars(const Macro::parser::location_type &l, const bool save) const;
|
||||||
|
|
||||||
//! Set a variable
|
//! Set a variable
|
||||||
void set_variable(const string &name, const MacroValue *value);
|
void set_variable(const string &name, MacroValuePtr value);
|
||||||
|
|
||||||
//! Replace "@{x}" with the value of x (if it exists in the environment) in a string
|
//! Replace "@{x}" with the value of x (if it exists in the environment) in a string
|
||||||
//! Check for variable existence first in func_env before checking in env
|
//! Check for variable existence first in func_env before checking in env
|
||||||
string replace_vars_in_str(const string &s) const;
|
string replace_vars_in_str(const string &s) const;
|
||||||
|
|
||||||
//! Set a function with arguments
|
//! Set a function with arguments
|
||||||
void set_string_function(const string &name, vector<string> &args, const MacroValue *value);
|
void set_string_function(const string &name, vector<string> &args, const MacroValuePtr &value);
|
||||||
|
|
||||||
//! Push function arguments onto func_env stack setting equal to NULL
|
//! Push function arguments onto func_env stack setting equal to NULL
|
||||||
void push_args_into_func_env(const vector<string> &args);
|
void push_args_into_func_env(const vector<string> &args);
|
||||||
|
@ -230,22 +221,21 @@ public:
|
||||||
void pop_func_env();
|
void pop_func_env();
|
||||||
|
|
||||||
//! Evaluate a function with arguments
|
//! Evaluate a function with arguments
|
||||||
const StringMV *eval_string_function(const string &name, const MacroValue *args);
|
MacroValuePtr eval_string_function(const string &name, const vector<MacroValuePtr> &args);
|
||||||
|
|
||||||
//! Get a variable
|
//! Get a variable
|
||||||
/*! Returns a newly allocated value (clone of the value stored in environment). */
|
MacroValuePtr get_variable(const string &name) const noexcept(false);
|
||||||
const MacroValue *get_variable(const string &name) const noexcept(false);
|
|
||||||
|
|
||||||
//! Initiate a for loop
|
//! Initiate a for loop
|
||||||
/*! Does not set name = value[1]. You must call iter_loop() for that. */
|
/*! Does not set name = value[1]. You must call iter_loop() for that. */
|
||||||
void init_loop(const string &name, const MacroValue *value) noexcept(false);
|
void init_loop(const string &name, MacroValuePtr value) noexcept(false);
|
||||||
|
|
||||||
//! Iterate innermost loop
|
//! Iterate innermost loop
|
||||||
/*! Returns false if iteration is no more possible (end of loop); in that case it destroys the pointer given to init_loop() */
|
/*! Returns false if iteration is no more possible (end of loop); in that case it destroys the pointer given to init_loop() */
|
||||||
bool iter_loop();
|
bool iter_loop();
|
||||||
|
|
||||||
//! Begins an @#if statement
|
//! Begins an @#if statement
|
||||||
void begin_if(const MacroValue *value) noexcept(false);
|
void begin_if(const MacroValuePtr &value) noexcept(false);
|
||||||
|
|
||||||
//! Begins an @#ifdef statement
|
//! Begins an @#ifdef statement
|
||||||
void begin_ifdef(const string &name);
|
void begin_ifdef(const string &name);
|
||||||
|
@ -254,10 +244,10 @@ public:
|
||||||
void begin_ifndef(const string &name);
|
void begin_ifndef(const string &name);
|
||||||
|
|
||||||
//! Executes @#echo directive
|
//! Executes @#echo directive
|
||||||
void echo(const Macro::parser::location_type &l, const MacroValue *value) const noexcept(false);
|
void echo(const Macro::parser::location_type &l, const MacroValuePtr &value) const noexcept(false);
|
||||||
|
|
||||||
//! Executes @#error directive
|
//! Executes @#error directive
|
||||||
void error(const Macro::parser::location_type &l, const MacroValue *value) const noexcept(false);
|
void error(const Macro::parser::location_type &l, const MacroValuePtr &value) const noexcept(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ! MACRO_DRIVER_HH
|
#endif // ! MACRO_DRIVER_HH
|
||||||
|
|
|
@ -102,7 +102,7 @@ CONT \\\\
|
||||||
if (string::npos != p)
|
if (string::npos != p)
|
||||||
pathvar.erase(p+1);
|
pathvar.erase(p+1);
|
||||||
|
|
||||||
string *includepath = NULL;
|
string *includepath = nullptr;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
includepath = new string(driver.get_variable(pathvar)->toString());
|
includepath = new string(driver.get_variable(pathvar)->toString());
|
||||||
|
@ -144,7 +144,7 @@ CONT \\\\
|
||||||
if (string::npos != p)
|
if (string::npos != p)
|
||||||
modvarname.erase(p+1);
|
modvarname.erase(p+1);
|
||||||
|
|
||||||
string *filename = NULL;
|
string *filename = nullptr;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
filename = new string(driver.get_variable(modvarname)->toString());
|
filename = new string(driver.get_variable(modvarname)->toString());
|
||||||
|
@ -204,7 +204,7 @@ CONT \\\\
|
||||||
<STMT,EXPR>{SPC}+ { yylloc->step(); }
|
<STMT,EXPR>{SPC}+ { yylloc->step(); }
|
||||||
|
|
||||||
<STMT,EXPR>[0-9]+ {
|
<STMT,EXPR>[0-9]+ {
|
||||||
yylval->int_val = atoi(yytext);
|
yylval->build<int>(atoi(yytext));
|
||||||
return token::INTEGER;
|
return token::INTEGER;
|
||||||
}
|
}
|
||||||
<STMT,EXPR>\( { return token::LPAREN; }
|
<STMT,EXPR>\( { return token::LPAREN; }
|
||||||
|
@ -231,8 +231,9 @@ CONT \\\\
|
||||||
<STMT,EXPR>length { return token::LENGTH; }
|
<STMT,EXPR>length { return token::LENGTH; }
|
||||||
|
|
||||||
<STMT,EXPR>\"[^\"]*\" {
|
<STMT,EXPR>\"[^\"]*\" {
|
||||||
yylval->string_val = new string(yytext + 1);
|
string s{yytext + 1};
|
||||||
yylval->string_val->resize(yylval->string_val->length() - 1);
|
s.resize(s.length() - 1);
|
||||||
|
yylval->build<string>(s);
|
||||||
return token::STRING;
|
return token::STRING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,7 +257,7 @@ CONT \\\\
|
||||||
<STMT>error { return token::ERROR; }
|
<STMT>error { return token::ERROR; }
|
||||||
|
|
||||||
<STMT,EXPR>[A-Za-z_][A-Za-z0-9_]* {
|
<STMT,EXPR>[A-Za-z_][A-Za-z0-9_]* {
|
||||||
yylval->string_val = new string(yytext);
|
yylval->build<string>(yytext);
|
||||||
return token::NAME;
|
return token::NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,442 +21,464 @@
|
||||||
|
|
||||||
#include "MacroDriver.hh"
|
#include "MacroDriver.hh"
|
||||||
|
|
||||||
MacroValue::MacroValue(MacroDriver &driver_arg) : driver(driver_arg)
|
MacroValuePtr
|
||||||
|
MacroValue::plus(const MacroValuePtr &mv) noexcept(false)
|
||||||
{
|
{
|
||||||
driver.values.insert(this);
|
throw TypeError("Operator + does not exist for this type");
|
||||||
}
|
}
|
||||||
|
|
||||||
MacroValue::~MacroValue()
|
MacroValuePtr
|
||||||
= default;
|
MacroValue::unary_plus() noexcept(false)
|
||||||
|
|
||||||
const MacroValue *
|
|
||||||
MacroValue::operator+() const noexcept(false)
|
|
||||||
{
|
{
|
||||||
throw TypeError("Unary operator + does not exist for this type");
|
throw TypeError("Unary operator + does not exist for this type");
|
||||||
}
|
}
|
||||||
|
|
||||||
const MacroValue *
|
MacroValuePtr
|
||||||
MacroValue::operator-(const MacroValue &mv) const noexcept(false)
|
MacroValue::minus(const MacroValuePtr &mv) noexcept(false)
|
||||||
{
|
{
|
||||||
throw TypeError("Operator - does not exist for this type");
|
throw TypeError("Operator - does not exist for this type");
|
||||||
}
|
}
|
||||||
|
|
||||||
const MacroValue *
|
MacroValuePtr
|
||||||
MacroValue::operator-() const noexcept(false)
|
MacroValue::unary_minus() noexcept(false)
|
||||||
{
|
{
|
||||||
throw TypeError("Unary operator - does not exist for this type");
|
throw TypeError("Unary operator - does not exist for this type");
|
||||||
}
|
}
|
||||||
|
|
||||||
const MacroValue *
|
MacroValuePtr
|
||||||
MacroValue::operator*(const MacroValue &mv) const noexcept(false)
|
MacroValue::times(const MacroValuePtr &mv) noexcept(false)
|
||||||
{
|
{
|
||||||
throw TypeError("Operator * does not exist for this type");
|
throw TypeError("Operator * does not exist for this type");
|
||||||
}
|
}
|
||||||
|
|
||||||
const MacroValue *
|
MacroValuePtr
|
||||||
MacroValue::operator/(const MacroValue &mv) const noexcept(false)
|
MacroValue::divide(const MacroValuePtr &mv) noexcept(false)
|
||||||
{
|
{
|
||||||
throw TypeError("Operator / does not exist for this type");
|
throw TypeError("Operator / does not exist for this type");
|
||||||
}
|
}
|
||||||
|
|
||||||
const MacroValue *
|
shared_ptr<IntMV>
|
||||||
MacroValue::operator<(const MacroValue &mv) const noexcept(false)
|
MacroValue::is_less(const MacroValuePtr &mv) noexcept(false)
|
||||||
{
|
{
|
||||||
throw TypeError("Operator < does not exist for this type");
|
throw TypeError("Operator < does not exist for this type");
|
||||||
}
|
}
|
||||||
|
|
||||||
const MacroValue *
|
shared_ptr<IntMV>
|
||||||
MacroValue::operator>(const MacroValue &mv) const noexcept(false)
|
MacroValue::is_greater(const MacroValuePtr &mv) noexcept(false)
|
||||||
{
|
{
|
||||||
throw TypeError("Operator > does not exist for this type");
|
throw TypeError("Operator > does not exist for this type");
|
||||||
}
|
}
|
||||||
|
|
||||||
const MacroValue *
|
shared_ptr<IntMV>
|
||||||
MacroValue::operator<=(const MacroValue &mv) const noexcept(false)
|
MacroValue::is_less_equal(const MacroValuePtr &mv) noexcept(false)
|
||||||
{
|
{
|
||||||
throw TypeError("Operator <= does not exist for this type");
|
throw TypeError("Operator <= does not exist for this type");
|
||||||
}
|
}
|
||||||
|
|
||||||
const MacroValue *
|
shared_ptr<IntMV>
|
||||||
MacroValue::operator>=(const MacroValue &mv) const noexcept(false)
|
MacroValue::is_greater_equal(const MacroValuePtr &mv) noexcept(false)
|
||||||
{
|
{
|
||||||
throw TypeError("Operator >= does not exist for this type");
|
throw TypeError("Operator >= does not exist for this type");
|
||||||
}
|
}
|
||||||
|
|
||||||
const MacroValue *
|
shared_ptr<IntMV>
|
||||||
MacroValue::operator&&(const MacroValue &mv) const noexcept(false)
|
MacroValue::is_different(const MacroValuePtr &mv)
|
||||||
|
{
|
||||||
|
if (is_equal(mv)->value)
|
||||||
|
return make_shared<IntMV>(0);
|
||||||
|
else
|
||||||
|
return make_shared<IntMV>(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_ptr<IntMV>
|
||||||
|
MacroValue::logical_and(const MacroValuePtr &mv) noexcept(false)
|
||||||
{
|
{
|
||||||
throw TypeError("Operator && does not exist for this type");
|
throw TypeError("Operator && does not exist for this type");
|
||||||
}
|
}
|
||||||
|
|
||||||
const MacroValue *
|
shared_ptr<IntMV>
|
||||||
MacroValue::operator||(const MacroValue &mv) const noexcept(false)
|
MacroValue::logical_or(const MacroValuePtr &mv) noexcept(false)
|
||||||
{
|
{
|
||||||
throw TypeError("Operator || does not exist for this type");
|
throw TypeError("Operator || does not exist for this type");
|
||||||
}
|
}
|
||||||
|
|
||||||
const MacroValue *
|
shared_ptr<IntMV>
|
||||||
MacroValue::operator!() const noexcept(false)
|
MacroValue::logical_not() noexcept(false)
|
||||||
{
|
{
|
||||||
throw TypeError("Operator ! does not exist for this type");
|
throw TypeError("Operator ! does not exist for this type");
|
||||||
}
|
}
|
||||||
|
|
||||||
const MacroValue *
|
MacroValuePtr
|
||||||
MacroValue::operator[](const MacroValue &mv) const noexcept(false)
|
MacroValue::subscript(const MacroValuePtr &mv) noexcept(false)
|
||||||
{
|
{
|
||||||
throw TypeError("Operator [] does not exist for this type");
|
throw TypeError("Operator [] does not exist for this type");
|
||||||
}
|
}
|
||||||
|
|
||||||
const MacroValue *
|
shared_ptr<IntMV>
|
||||||
MacroValue::length() const noexcept(false)
|
MacroValue::length() noexcept(false)
|
||||||
{
|
{
|
||||||
throw TypeError("Length not supported for this type");
|
throw TypeError("Length not supported for this type");
|
||||||
}
|
}
|
||||||
|
|
||||||
const MacroValue *
|
shared_ptr<IntMV>
|
||||||
MacroValue::at(int i) const noexcept(false)
|
MacroValue::in(const MacroValuePtr &mv) noexcept(false)
|
||||||
{
|
{
|
||||||
throw TypeError("Length not supported for this type");
|
throw TypeError("Second argument of 'in' operator must be an array");
|
||||||
}
|
}
|
||||||
|
|
||||||
const MacroValue *
|
IntMV::IntMV(int value_arg) : value{value_arg}
|
||||||
MacroValue::append(const MacroValue *mv) const noexcept(false)
|
|
||||||
{
|
|
||||||
throw TypeError("Cannot append an array at the end of another one. Should use concatenation.");
|
|
||||||
}
|
|
||||||
|
|
||||||
const MacroValue *
|
|
||||||
MacroValue::in(const MacroValue *array) const noexcept(false)
|
|
||||||
{
|
|
||||||
throw TypeError("First argument of 'in' operator cannot be an array");
|
|
||||||
}
|
|
||||||
|
|
||||||
const MacroValue *
|
|
||||||
MacroValue::new_base_value(MacroDriver &driver, int i)
|
|
||||||
{
|
|
||||||
return new IntMV(driver, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
const MacroValue *
|
|
||||||
MacroValue::new_base_value(MacroDriver &driver, const string &s)
|
|
||||||
{
|
|
||||||
return new StringMV(driver, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
IntMV::IntMV(MacroDriver &driver, int value_arg) : MacroValue(driver), value(value_arg)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
IntMV::~IntMV()
|
MacroValuePtr
|
||||||
= default;
|
IntMV::plus(const MacroValuePtr &mv) noexcept(false)
|
||||||
|
|
||||||
const MacroValue *
|
|
||||||
IntMV::operator+(const MacroValue &mv) const noexcept(false)
|
|
||||||
{
|
{
|
||||||
const auto *mv2 = dynamic_cast<const IntMV *>(&mv);
|
auto mv2 = dynamic_pointer_cast<IntMV>(mv);
|
||||||
if (mv2 == nullptr)
|
if (!mv2)
|
||||||
throw TypeError("Type mismatch for operands of + operator");
|
throw TypeError("Type mismatch for operands of + operator");
|
||||||
return new IntMV(driver, value + mv2->value);
|
return make_shared<IntMV>(value + mv2->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
const MacroValue *
|
MacroValuePtr
|
||||||
IntMV::operator+() const noexcept(false)
|
IntMV::unary_plus() noexcept(false)
|
||||||
{
|
{
|
||||||
return this;
|
return make_shared<IntMV>(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
const MacroValue *
|
MacroValuePtr
|
||||||
IntMV::operator-(const MacroValue &mv) const noexcept(false)
|
IntMV::minus(const MacroValuePtr &mv) noexcept(false)
|
||||||
{
|
{
|
||||||
const auto *mv2 = dynamic_cast<const IntMV *>(&mv);
|
auto mv2 = dynamic_pointer_cast<IntMV>(mv);
|
||||||
if (mv2 == nullptr)
|
if (!mv2)
|
||||||
throw TypeError("Type mismatch for operands of - operator");
|
throw TypeError("Type mismatch for operands of - operator");
|
||||||
return new IntMV(driver, value - mv2->value);
|
return make_shared<IntMV>(value - mv2->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
const MacroValue *
|
MacroValuePtr
|
||||||
IntMV::operator-() const noexcept(false)
|
IntMV::unary_minus() noexcept(false)
|
||||||
{
|
{
|
||||||
return new IntMV(driver, -value);
|
return make_shared<IntMV>(-value);
|
||||||
}
|
}
|
||||||
|
|
||||||
const MacroValue *
|
MacroValuePtr
|
||||||
IntMV::operator*(const MacroValue &mv) const noexcept(false)
|
IntMV::times(const MacroValuePtr &mv) noexcept(false)
|
||||||
{
|
{
|
||||||
const auto *mv2 = dynamic_cast<const IntMV *>(&mv);
|
auto mv2 = dynamic_pointer_cast<IntMV>(mv);
|
||||||
if (mv2 == nullptr)
|
if (!mv2)
|
||||||
throw TypeError("Type mismatch for operands of * operator");
|
throw TypeError("Type mismatch for operands of * operator");
|
||||||
return new IntMV(driver, value * mv2->value);
|
return make_shared<IntMV>(value * mv2->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
const MacroValue *
|
MacroValuePtr
|
||||||
IntMV::operator/(const MacroValue &mv) const noexcept(false)
|
IntMV::divide(const MacroValuePtr &mv) noexcept(false)
|
||||||
{
|
{
|
||||||
const auto *mv2 = dynamic_cast<const IntMV *>(&mv);
|
auto mv2 = dynamic_pointer_cast<IntMV>(mv);
|
||||||
if (mv2 == nullptr)
|
if (!mv2)
|
||||||
throw TypeError("Type mismatch for operands of / operator");
|
throw TypeError("Type mismatch for operands of / operator");
|
||||||
return new IntMV(driver, value / mv2->value);
|
if (!mv2->value)
|
||||||
|
throw DivisionByZeroError();
|
||||||
|
return make_shared<IntMV>(value / mv2->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
const MacroValue *
|
shared_ptr<IntMV>
|
||||||
IntMV::operator<(const MacroValue &mv) const noexcept(false)
|
IntMV::is_less(const MacroValuePtr &mv) noexcept(false)
|
||||||
{
|
{
|
||||||
const auto *mv2 = dynamic_cast<const IntMV *>(&mv);
|
auto mv2 = dynamic_pointer_cast<IntMV>(mv);
|
||||||
if (mv2 == nullptr)
|
if (!mv2)
|
||||||
throw TypeError("Type mismatch for operands of < operator");
|
throw TypeError("Type mismatch for operands of < operator");
|
||||||
return new IntMV(driver, value < mv2->value);
|
return make_shared<IntMV>(value < mv2->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
const MacroValue *
|
shared_ptr<IntMV>
|
||||||
IntMV::operator>(const MacroValue &mv) const noexcept(false)
|
IntMV::is_greater(const MacroValuePtr &mv) noexcept(false)
|
||||||
{
|
{
|
||||||
const auto *mv2 = dynamic_cast<const IntMV *>(&mv);
|
auto mv2 = dynamic_pointer_cast<IntMV>(mv);
|
||||||
if (mv2 == nullptr)
|
if (!mv2)
|
||||||
throw TypeError("Type mismatch for operands of > operator");
|
throw TypeError("Type mismatch for operands of > operator");
|
||||||
return new IntMV(driver, value > mv2->value);
|
return make_shared<IntMV>(value > mv2->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
const MacroValue *
|
shared_ptr<IntMV>
|
||||||
IntMV::operator<=(const MacroValue &mv) const noexcept(false)
|
IntMV::is_less_equal(const MacroValuePtr &mv) noexcept(false)
|
||||||
{
|
{
|
||||||
const auto *mv2 = dynamic_cast<const IntMV *>(&mv);
|
auto mv2 = dynamic_pointer_cast<IntMV>(mv);
|
||||||
if (mv2 == nullptr)
|
if (!mv2)
|
||||||
throw TypeError("Type mismatch for operands of <= operator");
|
throw TypeError("Type mismatch for operands of <= operator");
|
||||||
return new IntMV(driver, value <= mv2->value);
|
return make_shared<IntMV>(value <= mv2->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
const MacroValue *
|
shared_ptr<IntMV>
|
||||||
IntMV::operator>=(const MacroValue &mv) const noexcept(false)
|
IntMV::is_greater_equal(const MacroValuePtr &mv) noexcept(false)
|
||||||
{
|
{
|
||||||
const auto *mv2 = dynamic_cast<const IntMV *>(&mv);
|
auto mv2 = dynamic_pointer_cast<IntMV>(mv);
|
||||||
if (mv2 == nullptr)
|
if (!mv2)
|
||||||
throw TypeError("Type mismatch for operands of >= operator");
|
throw TypeError("Type mismatch for operands of >= operator");
|
||||||
return new IntMV(driver, value >= mv2->value);
|
return make_shared<IntMV>(value >= mv2->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
const MacroValue *
|
shared_ptr<IntMV>
|
||||||
IntMV::operator==(const MacroValue &mv) const noexcept(false)
|
IntMV::is_equal(const MacroValuePtr &mv)
|
||||||
{
|
{
|
||||||
const auto *mv2 = dynamic_cast<const IntMV *>(&mv);
|
auto mv2 = dynamic_pointer_cast<IntMV>(mv);
|
||||||
if (mv2 == nullptr)
|
if (!mv2)
|
||||||
return new IntMV(driver, 0);
|
return make_shared<IntMV>(0);
|
||||||
else
|
else
|
||||||
return new IntMV(driver, value == mv2->value);
|
return make_shared<IntMV>(value == mv2->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
const MacroValue *
|
shared_ptr<IntMV>
|
||||||
IntMV::operator!=(const MacroValue &mv) const noexcept(false)
|
IntMV::logical_and(const MacroValuePtr &mv) noexcept(false)
|
||||||
{
|
{
|
||||||
const auto *mv2 = dynamic_cast<const IntMV *>(&mv);
|
auto mv2 = dynamic_pointer_cast<IntMV>(mv);
|
||||||
if (mv2 == nullptr)
|
if (!mv2)
|
||||||
return new IntMV(driver, 1);
|
|
||||||
else
|
|
||||||
return new IntMV(driver, value != mv2->value);
|
|
||||||
}
|
|
||||||
|
|
||||||
const MacroValue *
|
|
||||||
IntMV::operator&&(const MacroValue &mv) const noexcept(false)
|
|
||||||
{
|
|
||||||
const auto *mv2 = dynamic_cast<const IntMV *>(&mv);
|
|
||||||
if (mv2 == nullptr)
|
|
||||||
throw TypeError("Type mismatch for operands of && operator");
|
throw TypeError("Type mismatch for operands of && operator");
|
||||||
return new IntMV(driver, value && mv2->value);
|
return make_shared<IntMV>(value && mv2->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
const MacroValue *
|
shared_ptr<IntMV>
|
||||||
IntMV::operator||(const MacroValue &mv) const noexcept(false)
|
IntMV::logical_or(const MacroValuePtr &mv) noexcept(false)
|
||||||
{
|
{
|
||||||
const auto *mv2 = dynamic_cast<const IntMV *>(&mv);
|
auto mv2 = dynamic_pointer_cast<IntMV>(mv);
|
||||||
if (mv2 == nullptr)
|
if (!mv2)
|
||||||
throw TypeError("Type mismatch for operands of || operator");
|
throw TypeError("Type mismatch for operands of || operator");
|
||||||
return new IntMV(driver, value || mv2->value);
|
return make_shared<IntMV>(value || mv2->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
const MacroValue *
|
shared_ptr<IntMV>
|
||||||
IntMV::operator!() const noexcept(false)
|
IntMV::logical_not() noexcept(false)
|
||||||
{
|
{
|
||||||
return new IntMV(driver, !value);
|
return make_shared<IntMV>(!value);
|
||||||
}
|
}
|
||||||
|
|
||||||
string
|
string
|
||||||
IntMV::toString() const
|
IntMV::toString()
|
||||||
{
|
{
|
||||||
return to_string(value);
|
return to_string(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
string
|
string
|
||||||
IntMV::print() const
|
IntMV::print()
|
||||||
{
|
{
|
||||||
return toString();
|
return toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
const MacroValue *
|
StringMV::StringMV(string value_arg) :
|
||||||
IntMV::toArray() const
|
value{move(value_arg)}
|
||||||
{
|
|
||||||
vector<int> v;
|
|
||||||
v.push_back(value);
|
|
||||||
return new ArrayMV<int>(driver, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
const MacroValue *
|
|
||||||
IntMV::append(const MacroValue *array) const noexcept(false)
|
|
||||||
{
|
|
||||||
const auto *array2 = dynamic_cast<const ArrayMV<int> *>(array);
|
|
||||||
if (array2 == nullptr)
|
|
||||||
throw TypeError("Type mismatch for append operation");
|
|
||||||
|
|
||||||
vector<int> v(array2->values);
|
|
||||||
v.push_back(value);
|
|
||||||
return new ArrayMV<int>(driver, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
const MacroValue *
|
|
||||||
IntMV::in(const MacroValue *array) const noexcept(false)
|
|
||||||
{
|
|
||||||
const auto *array2 = dynamic_cast<const ArrayMV<int> *>(array);
|
|
||||||
if (array2 == nullptr)
|
|
||||||
throw TypeError("Type mismatch for 'in' operator");
|
|
||||||
|
|
||||||
int result = 0;
|
|
||||||
for (int v : array2->values)
|
|
||||||
if (v == value)
|
|
||||||
{
|
|
||||||
result = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new IntMV(driver, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
const MacroValue *
|
|
||||||
IntMV::new_range(MacroDriver &driver, const MacroValue *mv1, const MacroValue *mv2) noexcept(false)
|
|
||||||
{
|
|
||||||
const auto *mv1i = dynamic_cast<const IntMV *>(mv1);
|
|
||||||
const auto *mv2i = dynamic_cast<const IntMV *>(mv2);
|
|
||||||
if (mv1i == nullptr || mv2i == nullptr)
|
|
||||||
throw TypeError("Arguments of range operator (:) must be integers");
|
|
||||||
|
|
||||||
int v1 = mv1i->value;
|
|
||||||
int v2 = mv2i->value;
|
|
||||||
|
|
||||||
vector<int> result;
|
|
||||||
for (; v1 <= v2; v1++)
|
|
||||||
result.push_back(v1);
|
|
||||||
return new ArrayMV<int>(driver, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
StringMV::StringMV(MacroDriver &driver, string value_arg) :
|
|
||||||
MacroValue(driver), value(move(value_arg))
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
StringMV::~StringMV()
|
MacroValuePtr
|
||||||
= default;
|
StringMV::plus(const MacroValuePtr &mv) noexcept(false)
|
||||||
|
|
||||||
const MacroValue *
|
|
||||||
StringMV::operator+(const MacroValue &mv) const noexcept(false)
|
|
||||||
{
|
{
|
||||||
const auto *mv2 = dynamic_cast<const StringMV *>(&mv);
|
auto mv2 = dynamic_pointer_cast<StringMV>(mv);
|
||||||
if (mv2 != nullptr)
|
if (mv2)
|
||||||
return new StringMV(driver, value + mv2->value);
|
return make_shared<StringMV>(value + mv2->value);
|
||||||
|
|
||||||
const auto *mv3 = dynamic_cast<const FuncMV *>(&mv);
|
|
||||||
if (mv3 != nullptr)
|
|
||||||
return new StringMV(driver, value + mv3->toString());
|
|
||||||
|
|
||||||
throw TypeError("Type mismatch for operands of + operator");
|
throw TypeError("Type mismatch for operands of + operator");
|
||||||
}
|
}
|
||||||
|
|
||||||
const MacroValue *
|
shared_ptr<IntMV>
|
||||||
StringMV::operator==(const MacroValue &mv) const noexcept(false)
|
StringMV::is_equal(const MacroValuePtr &mv)
|
||||||
{
|
{
|
||||||
const auto *mv2 = dynamic_cast<const StringMV *>(&mv);
|
auto mv2 = dynamic_pointer_cast<StringMV>(mv);
|
||||||
if (mv2 == nullptr)
|
if (mv2)
|
||||||
return new IntMV(driver, 0);
|
return make_shared<IntMV>(value == mv2->value);
|
||||||
else
|
else
|
||||||
return new IntMV(driver, value == mv2->value);
|
return make_shared<IntMV>(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const MacroValue *
|
MacroValuePtr
|
||||||
StringMV::operator!=(const MacroValue &mv) const noexcept(false)
|
StringMV::subscript(const MacroValuePtr &mv) noexcept(false)
|
||||||
{
|
{
|
||||||
const auto *mv2 = dynamic_cast<const StringMV *>(&mv);
|
|
||||||
if (mv2 == nullptr)
|
|
||||||
return new IntMV(driver, 1);
|
|
||||||
else
|
|
||||||
return new IntMV(driver, value != mv2->value);
|
|
||||||
}
|
|
||||||
|
|
||||||
const MacroValue *
|
|
||||||
StringMV::operator[](const MacroValue &mv) const noexcept(false)
|
|
||||||
{
|
|
||||||
const auto *mv2 = dynamic_cast<const ArrayMV<int> *>(&mv);
|
|
||||||
if (mv2 == nullptr)
|
|
||||||
throw TypeError("Expression inside [] must be an integer array");
|
|
||||||
string result;
|
string result;
|
||||||
for (int v : mv2->values)
|
|
||||||
{
|
auto copy_element = [&](int i) {
|
||||||
if (v < 1 || v > (int) value.length())
|
if (i < 1 || i > static_cast<int>(value.length()))
|
||||||
throw OutOfBoundsError();
|
throw OutOfBoundsError();
|
||||||
char c = value.at(v - 1);
|
result.append(1, value.at(i - 1));
|
||||||
result.append(1, c);
|
};
|
||||||
|
|
||||||
|
auto mv2 = dynamic_pointer_cast<IntMV>(mv);
|
||||||
|
auto mv3 = dynamic_pointer_cast<ArrayMV>(mv);
|
||||||
|
|
||||||
|
if (mv2)
|
||||||
|
copy_element(mv2->value);
|
||||||
|
else if (mv3)
|
||||||
|
for (auto &v : mv3->values)
|
||||||
|
{
|
||||||
|
auto v2 = dynamic_pointer_cast<IntMV>(v);
|
||||||
|
if (!v2)
|
||||||
|
throw TypeError("Expression inside [] must be an integer or an integer array");
|
||||||
|
copy_element(v2->value);
|
||||||
}
|
}
|
||||||
return new StringMV(driver, result);
|
else
|
||||||
|
throw TypeError("Expression inside [] must be an integer or an integer array");
|
||||||
|
|
||||||
|
return make_shared<StringMV>(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
string
|
string
|
||||||
StringMV::toString() const
|
StringMV::toString()
|
||||||
{
|
{
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
string
|
string
|
||||||
StringMV::print() const
|
StringMV::print()
|
||||||
{
|
{
|
||||||
return "'" + value + "'";
|
return "'" + value + "'";
|
||||||
}
|
}
|
||||||
|
|
||||||
const MacroValue *
|
FuncMV::FuncMV(vector<string> args_arg, string body_arg) :
|
||||||
StringMV::toArray() const
|
args{move(args_arg)}, body{move(body_arg)}
|
||||||
{
|
{
|
||||||
vector<string> v;
|
|
||||||
v.push_back(value);
|
|
||||||
return new ArrayMV<string>(driver, v);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const MacroValue *
|
shared_ptr<IntMV>
|
||||||
StringMV::append(const MacroValue *array) const noexcept(false)
|
FuncMV::is_equal(const MacroValuePtr &mv)
|
||||||
{
|
{
|
||||||
const auto *array2 = dynamic_cast<const ArrayMV<string> *>(array);
|
auto mv2 = dynamic_pointer_cast<FuncMV>(mv);
|
||||||
if (array2 == nullptr)
|
if (!mv2 || body != mv2->body)
|
||||||
throw TypeError("Type mismatch for append operation");
|
return make_shared<IntMV>(0);
|
||||||
|
|
||||||
vector<string> v(array2->values);
|
if (args.size() == mv2->args.size())
|
||||||
v.push_back(value);
|
for (size_t i = 0; i < args.size(); i++)
|
||||||
return new ArrayMV<string>(driver, v);
|
if (args[i] != mv2->args[i])
|
||||||
|
return make_shared<IntMV>(0);
|
||||||
|
|
||||||
|
return make_shared<IntMV>(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const MacroValue *
|
string
|
||||||
StringMV::in(const MacroValue *array) const noexcept(false)
|
FuncMV::toString()
|
||||||
{
|
{
|
||||||
const auto *array2 = dynamic_cast<const ArrayMV<string> *>(array);
|
return body;
|
||||||
if (array2 == nullptr)
|
}
|
||||||
throw TypeError("Type mismatch for 'in' operator");
|
|
||||||
|
|
||||||
int result = 0;
|
string
|
||||||
for (const auto &v : array2->values)
|
FuncMV::print()
|
||||||
if (v == value)
|
{
|
||||||
|
bool comma_flag = false;
|
||||||
|
string retval = "(";
|
||||||
|
for (auto it : args)
|
||||||
{
|
{
|
||||||
result = 1;
|
if (comma_flag)
|
||||||
|
retval += ", ";
|
||||||
|
retval += it;
|
||||||
|
comma_flag = true;
|
||||||
|
}
|
||||||
|
retval += ")";
|
||||||
|
return retval + " = '" + body + "'";
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayMV::ArrayMV(vector<MacroValuePtr> values_arg) : values{move(values_arg)}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MacroValuePtr
|
||||||
|
ArrayMV::plus(const MacroValuePtr &mv) noexcept(false)
|
||||||
|
{
|
||||||
|
auto mv2 = dynamic_pointer_cast<ArrayMV>(mv);
|
||||||
|
if (!mv2)
|
||||||
|
throw TypeError("Type mismatch for operands of + operator");
|
||||||
|
|
||||||
|
vector<MacroValuePtr> values_copy{values};
|
||||||
|
values_copy.insert(values_copy.end(), mv2->values.begin(), mv2->values.end());
|
||||||
|
return make_shared<ArrayMV>(values_copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
MacroValuePtr
|
||||||
|
ArrayMV::minus(const MacroValuePtr &mv) noexcept(false)
|
||||||
|
{
|
||||||
|
auto mv2 = dynamic_pointer_cast<ArrayMV>(mv);
|
||||||
|
if (!mv2)
|
||||||
|
throw TypeError("Type mismatch for operands of - operator");
|
||||||
|
|
||||||
|
/* Highly inefficient algorithm for computing set difference
|
||||||
|
(but vector<T> is not suited for that...) */
|
||||||
|
vector<MacroValuePtr> new_values;
|
||||||
|
for (auto &it : values)
|
||||||
|
{
|
||||||
|
auto it2 = mv2->values.cbegin();
|
||||||
|
for (; it2 != mv2->values.cend(); ++it2)
|
||||||
|
if (it->is_different(*it2)->value)
|
||||||
break;
|
break;
|
||||||
|
if (it2 == mv2->values.cend())
|
||||||
|
new_values.push_back(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new IntMV(driver, result);
|
return make_shared<ArrayMV>(new_values);
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_ptr<IntMV>
|
||||||
|
ArrayMV::is_equal(const MacroValuePtr &mv)
|
||||||
|
{
|
||||||
|
auto mv2 = dynamic_pointer_cast<ArrayMV>(mv);
|
||||||
|
if (!mv2 || values.size() != mv2->values.size())
|
||||||
|
return make_shared<IntMV>(0);
|
||||||
|
|
||||||
|
auto it = values.cbegin();
|
||||||
|
auto it2 = mv2->values.cbegin();
|
||||||
|
while (it != values.cend())
|
||||||
|
{
|
||||||
|
if ((*it)->is_different(*it2)->value)
|
||||||
|
return make_shared<IntMV>(0);
|
||||||
|
++it;
|
||||||
|
++it2;
|
||||||
|
}
|
||||||
|
return make_shared<IntMV>(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
MacroValuePtr
|
||||||
|
ArrayMV::subscript(const MacroValuePtr &mv) noexcept(false)
|
||||||
|
{
|
||||||
|
vector<MacroValuePtr> result;
|
||||||
|
|
||||||
|
auto copy_element = [&](int i) {
|
||||||
|
if (i < 1 || i > static_cast<int>(values.size()))
|
||||||
|
throw OutOfBoundsError();
|
||||||
|
result.push_back(values[i - 1]);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto mv2 = dynamic_pointer_cast<IntMV>(mv);
|
||||||
|
auto mv3 = dynamic_pointer_cast<ArrayMV>(mv);
|
||||||
|
|
||||||
|
if (mv2)
|
||||||
|
copy_element(mv2->value);
|
||||||
|
else if (mv3)
|
||||||
|
for (auto &v : mv3->values)
|
||||||
|
{
|
||||||
|
auto v2 = dynamic_pointer_cast<IntMV>(v);
|
||||||
|
if (!v2)
|
||||||
|
throw TypeError("Expression inside [] must be an integer or an integer array");
|
||||||
|
copy_element(v2->value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw TypeError("Expression inside [] must be an integer or an integer array");
|
||||||
|
|
||||||
|
if (result.size() > 1 || result.size() == 0)
|
||||||
|
return make_shared<ArrayMV>(result);
|
||||||
|
else
|
||||||
|
return result[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
|
||||||
string
|
string
|
||||||
ArrayMV<int>::print() const
|
ArrayMV::toString()
|
||||||
|
{
|
||||||
|
ostringstream ss;
|
||||||
|
for (auto &v : values)
|
||||||
|
ss << v->toString();
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_ptr<IntMV>
|
||||||
|
ArrayMV::length() noexcept(false)
|
||||||
|
{
|
||||||
|
return make_shared<IntMV>(values.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
string
|
||||||
|
ArrayMV::print()
|
||||||
{
|
{
|
||||||
ostringstream ss;
|
ostringstream ss;
|
||||||
ss << "[";
|
ss << "[";
|
||||||
|
@ -466,104 +488,40 @@ ArrayMV<int>::print() const
|
||||||
if (it != values.begin())
|
if (it != values.begin())
|
||||||
ss << ", ";
|
ss << ", ";
|
||||||
|
|
||||||
ss << *it;
|
ss << (*it)->print();
|
||||||
}
|
}
|
||||||
ss << "]";
|
ss << "]";
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
shared_ptr<ArrayMV>
|
||||||
string
|
ArrayMV::append(MacroValuePtr mv) noexcept(false)
|
||||||
ArrayMV<string>::print() const
|
|
||||||
{
|
{
|
||||||
ostringstream ss;
|
vector<MacroValuePtr> v{values};
|
||||||
ss << "{";
|
v.push_back(move(mv));
|
||||||
for (auto it = values.begin();
|
return make_shared<ArrayMV>(v);
|
||||||
it != values.end(); it++)
|
|
||||||
{
|
|
||||||
if (it != values.begin())
|
|
||||||
ss << ", ";
|
|
||||||
|
|
||||||
ss << "'" << *it << "'";
|
|
||||||
}
|
|
||||||
ss << "}";
|
|
||||||
return ss.str();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FuncMV::FuncMV(MacroDriver &driver, vector<string> &args_arg, StringMV &value_arg) :
|
shared_ptr<IntMV>
|
||||||
MacroValue(driver), args(args_arg), value(value_arg)
|
ArrayMV::in(const MacroValuePtr &mv) noexcept(false)
|
||||||
{
|
{
|
||||||
|
for (auto &v : values)
|
||||||
|
if (v->is_equal(mv)->value)
|
||||||
|
return make_shared<IntMV>(1);
|
||||||
|
|
||||||
|
return make_shared<IntMV>(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
FuncMV::~FuncMV()
|
shared_ptr<ArrayMV>
|
||||||
= default;
|
ArrayMV::range(const MacroValuePtr &mv1, const MacroValuePtr &mv2) noexcept(false)
|
||||||
|
|
||||||
const MacroValue *
|
|
||||||
FuncMV::operator+(const MacroValue &mv) const noexcept(false)
|
|
||||||
{
|
{
|
||||||
const auto *mv2 = dynamic_cast<const FuncMV *>(&mv);
|
auto mv1i = dynamic_pointer_cast<IntMV>(mv1);
|
||||||
if (mv2 != nullptr)
|
auto mv2i = dynamic_pointer_cast<IntMV>(mv2);
|
||||||
return value + mv2->value;
|
if (!mv1i || !mv2i)
|
||||||
|
throw TypeError("Arguments of range operator (:) must be integers");
|
||||||
|
|
||||||
const auto *mv3 = dynamic_cast<const StringMV *>(&mv);
|
vector<MacroValuePtr> result;
|
||||||
if (mv3 != nullptr)
|
for (int v1 = mv1i->value, v2 = mv2i->value; v1 <= v2; v1++)
|
||||||
return value + *mv3;
|
result.push_back(make_shared<IntMV>(v1));
|
||||||
|
return make_shared<ArrayMV>(result);
|
||||||
throw TypeError("Type mismatch for operands of + operator");
|
|
||||||
}
|
|
||||||
|
|
||||||
const MacroValue *
|
|
||||||
FuncMV::operator==(const MacroValue &mv) const noexcept(false)
|
|
||||||
{
|
|
||||||
const auto *mv2 = dynamic_cast<const FuncMV *>(&mv);
|
|
||||||
if (mv2 == nullptr)
|
|
||||||
return new IntMV(driver, 0);
|
|
||||||
|
|
||||||
if (value != mv2->value)
|
|
||||||
return new IntMV(driver, 0);
|
|
||||||
|
|
||||||
if (args.size() == mv2->args.size())
|
|
||||||
for (size_t i = 0; i < args.size(); i++)
|
|
||||||
if (args[i] != mv2->args[i])
|
|
||||||
return new IntMV(driver, 0);
|
|
||||||
|
|
||||||
return new IntMV(driver, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const MacroValue *
|
|
||||||
FuncMV::operator!=(const MacroValue &mv) const noexcept(false)
|
|
||||||
{
|
|
||||||
if (dynamic_cast<const IntMV *>(*this == mv)->value == 1)
|
|
||||||
return new IntMV(driver, 0);
|
|
||||||
return new IntMV(driver, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
string
|
|
||||||
FuncMV::toString() const
|
|
||||||
{
|
|
||||||
return value.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
string
|
|
||||||
FuncMV::print() const
|
|
||||||
{
|
|
||||||
bool comma_flag = false;
|
|
||||||
string retval = "(";
|
|
||||||
for (const auto it : args)
|
|
||||||
{
|
|
||||||
if (comma_flag)
|
|
||||||
retval += ", ";
|
|
||||||
retval += it;
|
|
||||||
comma_flag = true;
|
|
||||||
}
|
|
||||||
retval += ")";
|
|
||||||
return retval + " = '" + value.toString() + "'";
|
|
||||||
}
|
|
||||||
|
|
||||||
const MacroValue *
|
|
||||||
FuncMV::toArray() const
|
|
||||||
{
|
|
||||||
vector<string> v;
|
|
||||||
v.push_back(value.toString());
|
|
||||||
return new ArrayMV<string>(driver, v);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,24 +24,29 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
class MacroDriver;
|
class MacroDriver;
|
||||||
|
class MacroValue;
|
||||||
|
class IntMV;
|
||||||
|
class ArrayMV;
|
||||||
|
|
||||||
|
using MacroValuePtr = shared_ptr<MacroValue>;
|
||||||
|
|
||||||
//! Base class for representing values in macro language
|
//! Base class for representing values in macro language
|
||||||
|
/*! All its derived types are immutable, so that we don't need to carry const
|
||||||
|
qualifiers everywhere in the code */
|
||||||
class MacroValue
|
class MacroValue
|
||||||
{
|
{
|
||||||
protected:
|
|
||||||
//! Reference to enclosing MacroDriver
|
|
||||||
MacroDriver &driver;
|
|
||||||
public:
|
public:
|
||||||
//! Exception thrown when type error occurs in macro language
|
//! Exception thrown when type error occurs in macro language
|
||||||
class TypeError
|
class TypeError
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
const string message;
|
const string message;
|
||||||
TypeError(string message_arg) : message(move(message_arg))
|
TypeError(string message_arg) : message{move(message_arg)}
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -49,345 +54,161 @@ public:
|
||||||
class OutOfBoundsError
|
class OutOfBoundsError
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
MacroValue(MacroDriver &driver_arg);
|
//! Exception thrown when dividing by zero
|
||||||
virtual
|
class DivisionByZeroError
|
||||||
~MacroValue();
|
{
|
||||||
|
};
|
||||||
//! Applies + operator
|
//! Applies + operator
|
||||||
virtual const MacroValue *operator+(const MacroValue &mv) const noexcept(false) = 0;
|
virtual MacroValuePtr plus(const MacroValuePtr &mv) noexcept(false);
|
||||||
//! Applies unary + operator
|
//! Applies unary + operator
|
||||||
virtual const MacroValue *operator+() const noexcept(false);
|
virtual MacroValuePtr unary_plus() noexcept(false);
|
||||||
//! Applies - operator
|
//! Applies - operator
|
||||||
virtual const MacroValue *operator-(const MacroValue &mv) const noexcept(false);
|
virtual MacroValuePtr minus(const MacroValuePtr &mv) noexcept(false);
|
||||||
//! Applies unary - operator
|
//! Applies unary - operator
|
||||||
virtual const MacroValue *operator-() const noexcept(false);
|
virtual MacroValuePtr unary_minus() noexcept(false);
|
||||||
//! Applies * operator
|
//! Applies * operator
|
||||||
virtual const MacroValue *operator*(const MacroValue &mv) const noexcept(false);
|
virtual MacroValuePtr times(const MacroValuePtr &mv) noexcept(false);
|
||||||
//! Applies / operator
|
//! Applies / operator
|
||||||
virtual const MacroValue *operator/(const MacroValue &mv) const noexcept(false);
|
virtual MacroValuePtr divide(const MacroValuePtr &mv) noexcept(false);
|
||||||
//! Less comparison
|
//! Less comparison
|
||||||
/*! Returns an IntMV, equal to 0 or 1 */
|
/*! Returns an IntMV, equal to 0 or 1 */
|
||||||
virtual const MacroValue *operator<(const MacroValue &mv) const noexcept(false);
|
virtual shared_ptr<IntMV> is_less(const MacroValuePtr &mv) noexcept(false);
|
||||||
//! Greater comparision
|
//! Greater comparision
|
||||||
/*! Returns an IntMV, equal to 0 or 1 */
|
/*! Returns an IntMV, equal to 0 or 1 */
|
||||||
virtual const MacroValue *operator>(const MacroValue &mv) const noexcept(false);
|
virtual shared_ptr<IntMV> is_greater(const MacroValuePtr &mv) noexcept(false);
|
||||||
//! Less or equal comparison
|
//! Less or equal comparison
|
||||||
/*! Returns an IntMV, equal to 0 or 1 */
|
/*! Returns an IntMV, equal to 0 or 1 */
|
||||||
virtual const MacroValue *operator<=(const MacroValue &mv) const noexcept(false);
|
virtual shared_ptr<IntMV> is_less_equal(const MacroValuePtr &mv) noexcept(false);
|
||||||
//! Greater or equal comparison
|
//! Greater or equal comparison
|
||||||
/*! Returns an IntMV, equal to 0 or 1 */
|
/*! Returns an IntMV, equal to 0 or 1 */
|
||||||
virtual const MacroValue *operator>=(const MacroValue &mv) const noexcept(false);
|
virtual shared_ptr<IntMV> is_greater_equal(const MacroValuePtr &mv) noexcept(false);
|
||||||
//! Equal comparison
|
//! Equal comparison
|
||||||
/*! Returns an IntMV, equal to 0 or 1 */
|
/*! Returns an IntMV, equal to 0 or 1 */
|
||||||
virtual const MacroValue *operator==(const MacroValue &mv) const noexcept(false) = 0;
|
virtual shared_ptr<IntMV> is_equal(const MacroValuePtr &mv) = 0;
|
||||||
//! Not equal comparison
|
//! Not equal comparison
|
||||||
/*! Returns an IntMV, equal to 0 or 1 */
|
/*! Returns an IntMV, equal to 0 or 1 */
|
||||||
virtual const MacroValue *operator!=(const MacroValue &mv) const noexcept(false) = 0;
|
shared_ptr<IntMV> is_different(const MacroValuePtr &mv);
|
||||||
//! Applies && operator
|
//! Applies && operator
|
||||||
virtual const MacroValue *operator&&(const MacroValue &mv) const noexcept(false);
|
virtual shared_ptr<IntMV> logical_and(const MacroValuePtr &mv) noexcept(false);
|
||||||
//! Applies || operator
|
//! Applies || operator
|
||||||
virtual const MacroValue *operator||(const MacroValue &mv) const noexcept(false);
|
virtual shared_ptr<IntMV> logical_or(const MacroValuePtr &mv) noexcept(false);
|
||||||
//! Applies unary ! operator
|
//! Applies unary ! operator
|
||||||
virtual const MacroValue *operator!() const noexcept(false);
|
virtual shared_ptr<IntMV> logical_not() noexcept(false);
|
||||||
//! Applies [] operator
|
//! Applies [] operator
|
||||||
virtual const MacroValue *operator[](const MacroValue &mv) const noexcept(false);
|
virtual MacroValuePtr subscript(const MacroValuePtr &mv) noexcept(false);
|
||||||
//! Converts value to string
|
//! Converts value to string
|
||||||
virtual string toString() const = 0;
|
virtual string toString() = 0;
|
||||||
//! Converts value to be printed
|
//! Converts value to be printed
|
||||||
virtual string print() const = 0;
|
virtual string print() = 0;
|
||||||
//! Converts value to array form
|
|
||||||
virtual const MacroValue *toArray() const = 0;
|
|
||||||
//! Gets length
|
//! Gets length
|
||||||
virtual const MacroValue *length() const noexcept(false);
|
virtual shared_ptr<IntMV> length() noexcept(false);
|
||||||
//! Returns element at location i
|
|
||||||
virtual const MacroValue *at(int i) const noexcept(false);
|
|
||||||
//! Appends value at the end of an array
|
|
||||||
/*! The argument must be an array. */
|
|
||||||
virtual const MacroValue *append(const MacroValue *array) const noexcept(false);
|
|
||||||
//! Applies "in" operator
|
//! Applies "in" operator
|
||||||
/*! The argument must be an array. Returns an IntMV, equal to 0 or 1 */
|
/*! The argument is the element to be tested for inclusion. Returns an IntMV, equal to 0 or 1 */
|
||||||
virtual const MacroValue *in(const MacroValue *array) const noexcept(false);
|
virtual shared_ptr<IntMV> in(const MacroValuePtr &mv) noexcept(false);
|
||||||
//! Returns a new IntMV
|
|
||||||
/*! Necessary for ArrayMV::operator[] (template issue) */
|
|
||||||
static const MacroValue *new_base_value(MacroDriver &driver, int i);
|
|
||||||
//! Returns a new StringMV
|
|
||||||
/*! Necessary for ArrayMV::operator[] (template issue) */
|
|
||||||
static const MacroValue *new_base_value(MacroDriver &driver, const string &s);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Represents an integer value in macro language
|
//! Represents an integer value in macro language
|
||||||
class IntMV : public MacroValue
|
class IntMV : public MacroValue
|
||||||
{
|
{
|
||||||
friend class StringMV;
|
public:
|
||||||
friend class FuncMV;
|
IntMV(int value_arg);
|
||||||
friend class MacroDriver;
|
|
||||||
private:
|
|
||||||
//! Underlying integer value
|
//! Underlying integer value
|
||||||
const int value;
|
const int value;
|
||||||
public:
|
|
||||||
IntMV(MacroDriver &driver, int value_arg);
|
|
||||||
|
|
||||||
~IntMV() override;
|
|
||||||
//! Computes arithmetic addition
|
//! Computes arithmetic addition
|
||||||
const MacroValue *operator+(const MacroValue &mv) const noexcept(false) override;
|
MacroValuePtr plus(const MacroValuePtr &mv) noexcept(false) override;
|
||||||
//! Unary plus
|
//! Unary plus
|
||||||
/*! Returns itself */
|
/*! Returns itself */
|
||||||
const MacroValue *operator+() const noexcept(false) override;
|
MacroValuePtr unary_plus() noexcept(false) override;
|
||||||
//! Computes arithmetic substraction
|
//! Computes arithmetic substraction
|
||||||
const MacroValue *operator-(const MacroValue &mv) const noexcept(false) override;
|
MacroValuePtr minus(const MacroValuePtr &mv) noexcept(false) override;
|
||||||
//! Computes opposite
|
//! Computes opposite
|
||||||
const MacroValue *operator-() const noexcept(false) override;
|
MacroValuePtr unary_minus() noexcept(false) override;
|
||||||
//! Computes arithmetic multiplication
|
//! Computes arithmetic multiplication
|
||||||
const MacroValue *operator*(const MacroValue &mv) const noexcept(false) override;
|
MacroValuePtr times(const MacroValuePtr &mv) noexcept(false) override;
|
||||||
//! Computes arithmetic division
|
//! Computes arithmetic division
|
||||||
const MacroValue *operator/(const MacroValue &mv) const noexcept(false) override;
|
MacroValuePtr divide(const MacroValuePtr &mv) noexcept(false) override;
|
||||||
const MacroValue *operator<(const MacroValue &mv) const noexcept(false) override;
|
shared_ptr<IntMV> is_less(const MacroValuePtr &mv) noexcept(false) override;
|
||||||
const MacroValue *operator>(const MacroValue &mv) const noexcept(false) override;
|
shared_ptr<IntMV> is_greater(const MacroValuePtr &mv) noexcept(false) override;
|
||||||
const MacroValue *operator<=(const MacroValue &mv) const noexcept(false) override;
|
shared_ptr<IntMV> is_less_equal(const MacroValuePtr &mv) noexcept(false) override;
|
||||||
const MacroValue *operator>=(const MacroValue &mv) const noexcept(false) override;
|
shared_ptr<IntMV> is_greater_equal(const MacroValuePtr &mv) noexcept(false) override;
|
||||||
const MacroValue *operator==(const MacroValue &mv) const noexcept(false) override;
|
shared_ptr<IntMV> is_equal(const MacroValuePtr &mv) override;
|
||||||
const MacroValue *operator!=(const MacroValue &mv) const noexcept(false) override;
|
|
||||||
//! Computes logical and
|
//! Computes logical and
|
||||||
const MacroValue *operator&&(const MacroValue &mv) const noexcept(false) override;
|
shared_ptr<IntMV> logical_and(const MacroValuePtr &mv) noexcept(false) override;
|
||||||
//! Computes logical or
|
//! Computes logical or
|
||||||
const MacroValue *operator||(const MacroValue &mv) const noexcept(false) override;
|
shared_ptr<IntMV> logical_or(const MacroValuePtr &mv) noexcept(false) override;
|
||||||
//! Computes logical negation
|
//! Computes logical negation
|
||||||
const MacroValue *operator!() const noexcept(false) override;
|
shared_ptr<IntMV> logical_not() noexcept(false) override;
|
||||||
string toString() const override;
|
string toString() override;
|
||||||
string print() const override;
|
string print() override;
|
||||||
//! Converts value to array form
|
|
||||||
/*! Returns an integer array containing a single value */
|
|
||||||
const MacroValue *toArray() const override;
|
|
||||||
//! Appends value at the end of an array
|
|
||||||
/*! The first argument must be an integer array. */
|
|
||||||
const MacroValue *append(const MacroValue *array) const noexcept(false) override;
|
|
||||||
const MacroValue *in(const MacroValue *array) const noexcept(false) override;
|
|
||||||
//! Creates a integer range
|
|
||||||
/*! Arguments must be of type IntMV.
|
|
||||||
Returns an integer array containing all integers between mv1 and mv2.
|
|
||||||
If mv2 < mv1, returns an empty range (for consistency with MATLAB).
|
|
||||||
*/
|
|
||||||
static const MacroValue *new_range(MacroDriver &driver, const MacroValue *mv1, const MacroValue *mv2) noexcept(false);
|
|
||||||
inline int
|
|
||||||
get_int_value() const
|
|
||||||
{
|
|
||||||
return value;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Represents a string value in macro language
|
//! Represents a string value in macro language
|
||||||
class StringMV : public MacroValue
|
class StringMV : public MacroValue
|
||||||
{
|
{
|
||||||
friend class MacroDriver;
|
public:
|
||||||
private:
|
StringMV(string value_arg);
|
||||||
//! Underlying string value
|
//! Underlying string value
|
||||||
const string value;
|
const string value;
|
||||||
public:
|
|
||||||
StringMV(MacroDriver &driver, string value_arg);
|
|
||||||
|
|
||||||
~StringMV() override;
|
|
||||||
//! Computes string concatenation
|
//! Computes string concatenation
|
||||||
const MacroValue *operator+(const MacroValue &mv) const noexcept(false) override;
|
MacroValuePtr plus(const MacroValuePtr &mv) noexcept(false) override;
|
||||||
const MacroValue *operator==(const MacroValue &mv) const noexcept(false) override;
|
shared_ptr<IntMV> is_equal(const MacroValuePtr &mv) override;
|
||||||
const MacroValue *operator!=(const MacroValue &mv) const noexcept(false) override;
|
|
||||||
//! Subscripting operator
|
//! Subscripting operator
|
||||||
/*! Argument must be an ArrayMV<int>. Indexes begin at 1. Returns a StringMV. */
|
/*! Argument must be an ArrayMV<int>. Indexes begin at 1. Returns a StringMV. */
|
||||||
const MacroValue *operator[](const MacroValue &mv) const noexcept(false) override;
|
MacroValuePtr subscript(const MacroValuePtr &mv) noexcept(false) override;
|
||||||
//! Returns underlying string value
|
//! Returns underlying string value
|
||||||
string toString() const override;
|
string toString() override;
|
||||||
string print() const override;
|
string print() override;
|
||||||
//! Converts value to array form
|
|
||||||
/*! Returns a string array containing a single value */
|
|
||||||
const MacroValue *toArray() const override;
|
|
||||||
//! Appends value at the end of an array
|
|
||||||
/*! The first argument must be a string array. Returns a string array. */
|
|
||||||
const MacroValue *append(const MacroValue *array) const noexcept(false) override;
|
|
||||||
const MacroValue *in(const MacroValue *array) const noexcept(false) override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class FuncMV : public MacroValue
|
class FuncMV : public MacroValue
|
||||||
{
|
{
|
||||||
friend class MacroDriver;
|
public:
|
||||||
private:
|
FuncMV(vector<string> args, string body_arg);
|
||||||
//! Function args & body
|
//! Function args & body
|
||||||
const vector<string> args;
|
const vector<string> args;
|
||||||
const StringMV &value;
|
const string body;
|
||||||
public:
|
|
||||||
FuncMV(MacroDriver &driver, vector<string> &args, StringMV &value_arg);
|
|
||||||
|
|
||||||
~FuncMV() override;
|
shared_ptr<IntMV> is_equal(const MacroValuePtr &mv) override;
|
||||||
|
string toString() override;
|
||||||
//! Computes string concatenation
|
string print() override;
|
||||||
const MacroValue *operator+(const MacroValue &mv) const noexcept(false) override;
|
|
||||||
const MacroValue *operator==(const MacroValue &mv) const noexcept(false) override;
|
|
||||||
const MacroValue *operator!=(const MacroValue &mv) const noexcept(false) override;
|
|
||||||
string toString() const override;
|
|
||||||
string print() const override;
|
|
||||||
const MacroValue *toArray() const override;
|
|
||||||
inline const vector<string> &
|
|
||||||
get_args() const
|
|
||||||
{
|
|
||||||
return args;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Represents an array in macro language
|
//! Represents an array in macro language
|
||||||
template<typename T>
|
|
||||||
class ArrayMV : public MacroValue
|
class ArrayMV : public MacroValue
|
||||||
{
|
{
|
||||||
friend class IntMV;
|
|
||||||
friend class StringMV;
|
|
||||||
friend class ArrayMV<string>; // Necessary for operator[] to access values of integer array when subscripting a string array
|
|
||||||
friend class MacroDriver;
|
|
||||||
private:
|
|
||||||
//! Underlying vector
|
|
||||||
const vector<T> values;
|
|
||||||
public:
|
public:
|
||||||
ArrayMV(MacroDriver &driver, vector<T> values_arg);
|
ArrayMV(vector<MacroValuePtr> values_arg);
|
||||||
|
|
||||||
|
//! Underlying vector
|
||||||
|
const vector<MacroValuePtr> values;
|
||||||
|
|
||||||
~ArrayMV() override;
|
|
||||||
//! Computes array concatenation
|
//! Computes array concatenation
|
||||||
/*! Both array must be of same type */
|
/*! Both array must be of same type */
|
||||||
const MacroValue *operator+(const MacroValue &mv) const noexcept(false) override;
|
MacroValuePtr plus(const MacroValuePtr &mv) noexcept(false) override;
|
||||||
//! Returns an array in which the elements of the second array have been removed from the first
|
//! Returns an array in which the elements of the second array have been removed from the first
|
||||||
/*! It is close to a set difference operation, except that if an element appears two times in the first array, it will also be in the returned value (provided it is not in the second array) */
|
/*! It is close to a set difference operation, except that if an element appears two times in the first array, it will also be in the returned value (provided it is not in the second array) */
|
||||||
const MacroValue *operator-(const MacroValue &mv) const noexcept(false) override;
|
MacroValuePtr minus(const MacroValuePtr &mv) noexcept(false) override;
|
||||||
const MacroValue *operator==(const MacroValue &mv) const noexcept(false) override;
|
shared_ptr<IntMV> is_equal(const MacroValuePtr &mv) override;
|
||||||
const MacroValue *operator!=(const MacroValue &mv) const noexcept(false) override;
|
|
||||||
//! Subscripting operator
|
//! Subscripting operator
|
||||||
/*! Argument must be an ArrayMV<int>. Indexes begin at 1.
|
/*! Argument must be an ArrayMV<int>. Indexes begin at 1.
|
||||||
If argument is a one-element array, returns an IntMV or StringMV.
|
If argument is a one-element array, returns an IntMV or StringMV.
|
||||||
Otherwise returns an array. */
|
Otherwise returns an array. */
|
||||||
const MacroValue *operator[](const MacroValue &mv) const noexcept(false) override;
|
MacroValuePtr subscript(const MacroValuePtr &mv) noexcept(false) override;
|
||||||
//! Returns a string containing the concatenation of string representations of elements
|
//! Returns a string containing the concatenation of string representations of elements
|
||||||
string toString() const override;
|
string toString() override;
|
||||||
string print() const override;
|
string print() override;
|
||||||
//! Returns itself
|
|
||||||
const MacroValue *toArray() const override;
|
|
||||||
//! Gets length
|
//! Gets length
|
||||||
const MacroValue *length() const noexcept(false) override;
|
shared_ptr<IntMV> length() noexcept(false) override;
|
||||||
const MacroValue *at(int i) const noexcept(false) override;
|
shared_ptr<ArrayMV> append(MacroValuePtr mv) noexcept(false);
|
||||||
|
shared_ptr<IntMV> in(const MacroValuePtr &mv) noexcept(false) override;
|
||||||
|
/*! Arguments must be of type IntMV.
|
||||||
|
Returns an integer array containing all integers between mv1 and mv2.
|
||||||
|
If mv2 < mv1, returns an empty range (for consistency with MATLAB).
|
||||||
|
*/
|
||||||
|
static shared_ptr<ArrayMV> range(const MacroValuePtr &mv1, const MacroValuePtr &mv2) noexcept(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ArrayMV<T>::ArrayMV(MacroDriver &driver, vector<T> values_arg) : MacroValue(driver), values(move(values_arg))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ArrayMV<T>::~ArrayMV()
|
|
||||||
= default;
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
const MacroValue *
|
|
||||||
ArrayMV<T>::operator+(const MacroValue &mv) const noexcept(false)
|
|
||||||
{
|
|
||||||
const auto *mv2 = dynamic_cast<const ArrayMV<T> *>(&mv);
|
|
||||||
if (mv2 == nullptr)
|
|
||||||
throw TypeError("Type mismatch for operands of + operator");
|
|
||||||
|
|
||||||
vector<T> values_copy(values);
|
|
||||||
values_copy.insert(values_copy.end(), mv2->values.begin(), mv2->values.end());
|
|
||||||
return new ArrayMV<T>(driver, values_copy);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
const MacroValue *
|
|
||||||
ArrayMV<T>::operator-(const MacroValue &mv) const noexcept(false)
|
|
||||||
{
|
|
||||||
const auto *mv2 = dynamic_cast<const ArrayMV<T> *>(&mv);
|
|
||||||
if (mv2 == nullptr)
|
|
||||||
throw TypeError("Type mismatch for operands of - operator");
|
|
||||||
|
|
||||||
/* Highly inefficient algorithm for computing set difference
|
|
||||||
(but vector<T> is not suited for that...) */
|
|
||||||
vector<T> new_values;
|
|
||||||
for (auto it = values.begin();
|
|
||||||
it != values.end(); it++)
|
|
||||||
{
|
|
||||||
typename vector<T>::const_iterator it2;
|
|
||||||
for (it2 = mv2->values.begin(); it2 != mv2->values.end(); it2++)
|
|
||||||
if (*it == *it2)
|
|
||||||
break;
|
|
||||||
if (it2 == mv2->values.end())
|
|
||||||
new_values.push_back(*it);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ArrayMV<T>(driver, new_values);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
const MacroValue *
|
|
||||||
ArrayMV<T>::operator==(const MacroValue &mv) const noexcept(false)
|
|
||||||
{
|
|
||||||
const auto *mv2 = dynamic_cast<const ArrayMV<T> *>(&mv);
|
|
||||||
if (mv2 == nullptr)
|
|
||||||
return new IntMV(driver, 0);
|
|
||||||
else
|
|
||||||
return new IntMV(driver, values == mv2->values);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
const MacroValue *
|
|
||||||
ArrayMV<T>::operator!=(const MacroValue &mv) const noexcept(false)
|
|
||||||
{
|
|
||||||
const auto *mv2 = dynamic_cast<const ArrayMV<T> *>(&mv);
|
|
||||||
if (mv2 == nullptr)
|
|
||||||
return new IntMV(driver, 1);
|
|
||||||
else
|
|
||||||
return new IntMV(driver, values != mv2->values);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
const MacroValue *
|
|
||||||
ArrayMV<T>::operator[](const MacroValue &mv) const noexcept(false)
|
|
||||||
{
|
|
||||||
const auto *mv2 = dynamic_cast<const ArrayMV<int> *>(&mv);
|
|
||||||
if (mv2 == nullptr)
|
|
||||||
throw TypeError("Expression inside [] must be an integer array");
|
|
||||||
vector<T> result;
|
|
||||||
for (int value : mv2->values)
|
|
||||||
{
|
|
||||||
if (value < 1 || value > (int) values.size())
|
|
||||||
throw OutOfBoundsError();
|
|
||||||
result.push_back(values[value - 1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result.size() > 1 || result.size() == 0)
|
|
||||||
return new ArrayMV<T>(driver, result);
|
|
||||||
else
|
|
||||||
return MacroValue::new_base_value(driver, result[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
string
|
|
||||||
ArrayMV<T>::toString() const
|
|
||||||
{
|
|
||||||
ostringstream ss;
|
|
||||||
for (auto it = values.begin();
|
|
||||||
it != values.end(); it++)
|
|
||||||
ss << *it;
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
const MacroValue *
|
|
||||||
ArrayMV<T>::toArray() const
|
|
||||||
{
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
const MacroValue *
|
|
||||||
ArrayMV<T>::length() const noexcept(false)
|
|
||||||
{
|
|
||||||
return new IntMV(driver, values.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
const MacroValue *
|
|
||||||
ArrayMV<T>::at(int i) const noexcept(false)
|
|
||||||
{
|
|
||||||
return new_base_value(driver, values[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue