From dc45be0651e80ef695f37932189ee7e93fd6262c Mon Sep 17 00:00:00 2001
From: Andrea Franchini <hello@andreafranchini.com>
Date: Mon, 30 Jan 2023 15:14:27 +0100
Subject: [PATCH] Add rel_attr_elem_expr, parses vm1.x == vm2.y

---
 mc_openapi/doml_mc/domlr_parser/parser.py     | 65 ++++++++++++++++---
 .../example_single_req_qty_comparison.domlr   | 27 +++++---
 2 files changed, 75 insertions(+), 17 deletions(-)

diff --git a/mc_openapi/doml_mc/domlr_parser/parser.py b/mc_openapi/doml_mc/domlr_parser/parser.py
index d5d3edb..ef34a54 100644
--- a/mc_openapi/doml_mc/domlr_parser/parser.py
+++ b/mc_openapi/doml_mc/domlr_parser/parser.py
@@ -178,7 +178,7 @@ class DOMLRTransformer(Transformer):
         return _gen_rel_elem_expr
 
     def rel_attr_value_expr(self, args):
-        """An ATTRIBUTE relationship"""
+        """An ATTRIBUTE relationship with a rhs that is a value"""
 
         rel_name = args[1].value
         def _gen_rel_attr_value_expr(enc: SMTEncoding, sorts: SMTSorts):
@@ -219,15 +219,62 @@ class DOMLRTransformer(Transformer):
         return _gen_rel_attr_value_expr
 
     def rel_attr_elem_expr(self, args):
-        """Parse rhs of expression containing:
-           <, <=, >, >=, ==, != can be followed by a NUMBER
-           ==, != can be followed by a BOOL or STRING
-           should generate attr(e1, rel, attr_data_sort(VALUE)) for ==, !=
-           or attr(e1, rel, val) and get_int(val) >= NUMBER
+        """An ATTRIBUTE relationship with a rhs that is another element"""
 
-        """
-        print("rel_attr_elem_expr", args)
-        return args
+        rel1_name = args[1].value
+        rel2_name = args[4].value
+        op = args[2].value
+
+        def _gen_rel_attr_elem_expr(enc: SMTEncoding, sorts: SMTSorts):
+            elem1 = RefHandler.get_const(args[0].value, sorts)
+            elem2 = RefHandler.get_const(args[3].value, sorts)
+            rel1, rel1_type = RefHandler.get_relationship(enc, rel1_name)
+            rel2, rel2_type = RefHandler.get_relationship(enc, rel2_name)
+
+            assert rel1_type == RefHandler.ATTRIBUTE
+            assert rel2_type == RefHandler.ATTRIBUTE
+
+            rhs_value = RefHandler.get_value("x", sorts)
+
+            expr = And(
+                RefHandler.get_attribute_rel(enc,
+                    elem1,
+                    rel1,
+                    rhs_value
+                ),
+                RefHandler.get_attribute_rel(enc,
+                    elem2,
+                    rel2,
+                    rhs_value
+                )
+            )
+            if op == "==":
+                return expr
+            elif op == "!=":
+                return Not(expr)
+            else:
+                rhs1_value = RefHandler.get_value("rhs1", sorts)
+                rhs2_value = RefHandler.get_value("rhs2", sorts)
+                expr = And(
+                    RefHandler.get_attribute_rel(enc,
+                        elem1,
+                        rel1,
+                        rhs1_value
+                    ),
+                    RefHandler.get_attribute_rel(enc,
+                        elem2,
+                        rel2,
+                        rhs2_value
+                    ),
+                    self.compare_int(sorts, op, rhs1_value, rhs2_value)
+                )
+                print(
+                    "Warning: Comparing attributes of two elements with {op} is experimental!\n",
+                    "Assumption: the attribute is an Integer."
+                )
+                return expr            
+
+        return _gen_rel_attr_elem_expr
 
     def _get_equality_sides(self, arg1, arg2):
         # We track use of const in const_or_class
diff --git a/tests/domlr/example_single_req_qty_comparison.domlr b/tests/domlr/example_single_req_qty_comparison.domlr
index 09e1f43..9d7029d 100644
--- a/tests/domlr/example_single_req_qty_comparison.domlr
+++ b/tests/domlr/example_single_req_qty_comparison.domlr
@@ -9,16 +9,27 @@
 #     )
 # )
 
+# OLD SYNTAX
+# +   "All VMs have at least 512 MB of memory"
+#     forall vm (
+#         vm is class infrastructure.VirtualMachine
+#         implies
+#         (
+#             vm has abstract.ComputingNode.memory_mb Mem
+#             and
+#             Mem < 512
+#         )
+#     )
+    
+#     ---
+#     "All VMs have at least 256 MB of memory"
+
 +   "All VMs have at least 512 MB of memory"
     forall vm (
         vm is class infrastructure.VirtualMachine
-        implies
-        (
-            vm has abstract.ComputingNode.memory_mb Mem
-            and
-            Mem < 512
-        )
+        implies    
+        vm has abstract.ComputingNode.memory_mb >= 512
+        
     )
     
-    ---
-    "All VMs have at least 256 MB of memory"
+    error: "All VMs have at least 256 MB of memory"
\ No newline at end of file
-- 
GitLab