diff --git a/src/macro/MacroBison.yy b/src/macro/MacroBison.yy index a2b245836d51027e10872d9f6889cb846484228a..41359488ef6d5bbb2a672f5e92efeb9c2dfe6b25 100644 --- a/src/macro/MacroBison.yy +++ b/src/macro/MacroBison.yy @@ -84,7 +84,7 @@ class MacroDriver; %type <vector<string>> func_args %type <MacroValuePtr> expr -%type <vector<MacroValuePtr>> comma_expr +%type <vector<MacroValuePtr>> comma_expr tuple_comma_expr %% %start statement_list_or_nothing; @@ -136,6 +136,8 @@ expr : INTEGER { $$ = make_shared<IntMV>($1); } | STRING { $$ = make_shared<StringMV>(driver.replace_vars_in_str($1)); } + | LPAREN tuple_comma_expr RPAREN + { $$ = make_shared<TupleMV>($2); } | NAME { try @@ -213,6 +215,16 @@ comma_expr : %empty { $1.push_back($3); $$ = $1; } ; +tuple_comma_expr : %empty + { $$ = vector<MacroValuePtr>{}; } // Empty array + | expr COMMA + { $$ = vector<MacroValuePtr>{$1}; } + | expr COMMA expr + { $$ = vector<MacroValuePtr>{$1, $3}; } + | tuple_comma_expr COMMA expr + { $1.push_back($3); $$ = $1; } + ; + %% void diff --git a/src/macro/MacroValue.cc b/src/macro/MacroValue.cc index 4d1f0ca05f146ea96f3483bffc9c36cf36ee1ca3..739ca7954dd80913431c4276b50116e671520481 100644 --- a/src/macro/MacroValue.cc +++ b/src/macro/MacroValue.cc @@ -531,3 +531,110 @@ ArrayMV::range(const MacroValuePtr &mv1, const MacroValuePtr &mv2) noexcept(fals result.push_back(make_shared<IntMV>(v1)); return make_shared<ArrayMV>(result); } + +TupleMV::TupleMV(vector<MacroValuePtr> values_arg) : values{move(values_arg)} +{ +} + +shared_ptr<IntMV> +TupleMV::is_equal(const MacroValuePtr &mv) +{ + auto mv2 = dynamic_pointer_cast<TupleMV>(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 +TupleMV::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<TupleMV>(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<TupleMV>(result); + else + return result[0]; +} + +string +TupleMV::toString() +{ + ostringstream ss; + bool print_comma = false; + ss << "("; + for (auto &v : values) + { + if (print_comma) + ss << ", "; + else + print_comma = true; + ss << v->toString(); + } + ss << ")"; + return ss.str(); +} + +shared_ptr<IntMV> +TupleMV::length() noexcept(false) +{ + return make_shared<IntMV>(values.size()); +} + +string +TupleMV::print() +{ + ostringstream ss; + ss << "("; + for (auto it = values.begin(); + it != values.end(); it++) + { + if (it != values.begin()) + ss << ", "; + + ss << (*it)->print(); + } + ss << ")"; + return ss.str(); +} + +shared_ptr<IntMV> +TupleMV::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); +} diff --git a/src/macro/MacroValue.hh b/src/macro/MacroValue.hh index 35c9c934d956bc75fb18db07f0ee01bb237b90cb..051ec6143b44c15c369d5ef1162594b62e04a0fe 100644 --- a/src/macro/MacroValue.hh +++ b/src/macro/MacroValue.hh @@ -212,4 +212,24 @@ public: static shared_ptr<ArrayMV> range(const MacroValuePtr &mv1, const MacroValuePtr &mv2) noexcept(false); }; +//! Represents a tuple value in macro language +class TupleMV : public MacroValue +{ +public: + TupleMV(vector<MacroValuePtr> values_arg); + + //! Underlying vector + const vector<MacroValuePtr> values; + + shared_ptr<IntMV> is_equal(const MacroValuePtr &mv) override; + //! Subscripting operator + /*! Argument must be an ArrayMV<int>. Indexes begin at 1. Returns a StringMV. */ + MacroValuePtr subscript(const MacroValuePtr &mv) noexcept(false) override; + //! Returns underlying string value + string toString() override; + string print() override; + shared_ptr<IntMV> length() noexcept(false) override; + shared_ptr<IntMV> in(const MacroValuePtr &mv) noexcept(false) override; +}; + #endif