From 039b27bbafa66ca8251691dd8107412f7ec59eed Mon Sep 17 00:00:00 2001
From: Houtan Bastani <houtan@dynare.org>
Date: Tue, 7 Aug 2018 12:40:59 +0200
Subject: [PATCH] macroprocessor: union operator. #5

---
 src/macro/MacroBison.yy |  4 +++-
 src/macro/MacroFlex.ll  |  1 +
 src/macro/MacroValue.cc | 30 ++++++++++++++++++++++++++++++
 src/macro/MacroValue.hh |  3 +++
 4 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/src/macro/MacroBison.yy b/src/macro/MacroBison.yy
index 41359488..5b9bac62 100644
--- a/src/macro/MacroBison.yy
+++ b/src/macro/MacroBison.yy
@@ -78,7 +78,7 @@ class MacroDriver;
 %nonassoc IN
 %nonassoc COLON
 %left PLUS MINUS
-%left TIMES DIVIDE
+%left TIMES DIVIDE UNION
 %precedence UMINUS UPLUS EXCLAMATION
 %precedence LBRACKET
 
@@ -205,6 +205,8 @@ expr : INTEGER
        { TYPERR_CATCH($$ = ArrayMV::range($1, $3), @$); }
      | expr IN expr
        { TYPERR_CATCH($$ = $3->in($1), @$); }
+     | expr UNION expr
+       { TYPERR_CATCH($$ = $1->set_union($3), @$); }
      ;
 
 comma_expr : %empty
diff --git a/src/macro/MacroFlex.ll b/src/macro/MacroFlex.ll
index 1db33cb6..8dae3b4a 100644
--- a/src/macro/MacroFlex.ll
+++ b/src/macro/MacroFlex.ll
@@ -218,6 +218,7 @@ CONT \\\\
 <STMT,EXPR>[!]              { return token::EXCLAMATION; }
 <STMT,EXPR>"||"             { return token::LOGICAL_OR; }
 <STMT,EXPR>&&               { return token::LOGICAL_AND; }
+<STMT,EXPR>"|"              { return token::UNION; }
 <STMT,EXPR>"<="             { return token::LESS_EQUAL; }
 <STMT,EXPR>">="             { return token::GREATER_EQUAL; }
 <STMT,EXPR>"<"              { return token::LESS; }
diff --git a/src/macro/MacroValue.cc b/src/macro/MacroValue.cc
index 739ca795..e64ae065 100644
--- a/src/macro/MacroValue.cc
+++ b/src/macro/MacroValue.cc
@@ -126,6 +126,12 @@ MacroValue::in(const MacroValuePtr &mv) noexcept(false)
   throw TypeError("Second argument of 'in' operator must be an array");
 }
 
+shared_ptr<ArrayMV>
+MacroValue::set_union(const MacroValuePtr &mv) noexcept(false)
+{
+  throw TypeError("Operator | does not exist for this type");
+}
+
 IntMV::IntMV(int value_arg) : value{value_arg}
 {
 }
@@ -532,6 +538,30 @@ ArrayMV::range(const MacroValuePtr &mv1, const MacroValuePtr &mv2) noexcept(fals
   return make_shared<ArrayMV>(result);
 }
 
+shared_ptr<ArrayMV>
+ArrayMV::set_union(const MacroValuePtr &mv) noexcept(false)
+{
+  auto mv2 = dynamic_pointer_cast<ArrayMV>(mv);
+  if (!mv2)
+    throw TypeError("Arguments of the union operator (|) must be sets");
+
+  vector<MacroValuePtr> new_values = values;
+  for (auto &it : mv2->values)
+    {
+      bool found = false;
+      for (auto &nvit : new_values)
+        if (nvit->is_equal(it)->value)
+          {
+            found = true;
+            break;
+          }
+      if (!found)
+        new_values.push_back(it);
+    }
+
+  return make_shared<ArrayMV>(new_values);
+}
+
 TupleMV::TupleMV(vector<MacroValuePtr> values_arg) : values{move(values_arg)}
 {
 }
diff --git a/src/macro/MacroValue.hh b/src/macro/MacroValue.hh
index 051ec614..a26b466b 100644
--- a/src/macro/MacroValue.hh
+++ b/src/macro/MacroValue.hh
@@ -105,6 +105,8 @@ public:
   //! Applies "in" operator
   /*! The argument is the element to be tested for inclusion. Returns an IntMV, equal to 0 or 1 */
   virtual shared_ptr<IntMV> in(const MacroValuePtr &mv) noexcept(false);
+  //! Creates the union of two sets
+  virtual shared_ptr<ArrayMV> set_union(const MacroValuePtr &mv) noexcept(false);
 };
 
 //! Represents an integer value in macro language
@@ -210,6 +212,7 @@ public:
     If mv2 < mv1, returns an empty range (for consistency with MATLAB).
   */
   static shared_ptr<ArrayMV> range(const MacroValuePtr &mv1, const MacroValuePtr &mv2) noexcept(false);
+  shared_ptr<ArrayMV> set_union(const MacroValuePtr &mvp) noexcept(false) override;
 };
 
 //! Represents a tuple value in macro language
-- 
GitLab