Browse Source

Added constraints and added some test cases

Yentl Van Tendeloo 8 years ago
parent
commit
ef986ecd53

+ 1 - 0
integration/code/my_petrinet_with_MM.mvc

@@ -1,4 +1,5 @@
 import models/SimpleClassDiagrams as SCD
+include "primitives.alh"
 
 SCD PetriNets{
     Class Natural {}

+ 43 - 0
integration/code/my_petrinet_with_MM_and_constraints.mvc

@@ -0,0 +1,43 @@
+import models/SimpleClassDiagrams as SCD
+include "primitives.alh"
+
+SCD PetriNets{
+    Class Natural {
+        $
+            if (bool_not(is_physical_int(self))):
+                return "Natural has no integer value"
+            elif (integer_lt(self, 0)):
+                return "Natural does not have a positive or zero value"
+            else:
+                return "OK"
+         $
+    }
+    Class Place{
+        tokens : Natural
+    }
+    Class Transition{}
+    Association P2T (Place, Transition) {
+        weight : Natural
+    }
+    Association T2P (Transition, Place) {
+        weight : Natural
+    }
+}
+
+PetriNets my_petrinet {
+    Place p1 {
+        tokens = 1
+    }
+    Place p2 {
+        tokens = 3
+    }
+    Transition t1 {}
+    P2T (p1, t1) {
+        weight = 1
+    }
+    T2P (t1, p2) {
+        weight = 2
+    }
+}
+
+export my_petrinet to models/my_petrinet

+ 27 - 0
integration/code/petrinets_constraints.mvc

@@ -0,0 +1,27 @@
+import models/SimpleClassDiagrams as SCD
+include "primitives.alh"
+
+SCD PetriNets{
+    Class Natural {
+        $
+            if (bool_not(is_physical_int(self))):
+                return "Natural has no integer value"
+            elif (integer_lt(self, 0)):
+                return "Natural does not have a positive or zero value"
+            else:
+                return "OK"
+         $
+    }
+    Class Place{
+        tokens : Natural
+    }
+    Class Transition{}
+    Association P2T (Place, Transition) {
+        weight : Natural
+    }
+    Association T2P (Transition, Place) {
+        weight : Natural
+    }
+}
+
+export PetriNets to models/PetriNets

+ 33 - 0
integration/my_petrinet_with_MM_and_constraints.mvc

@@ -0,0 +1,33 @@
+import models/SimpleClassDiagrams as SCD
+
+SCD PetriNets{
+    Class Natural {}
+    Class Place{
+        tokens : Natural
+    }
+    Class Transition{}
+    Association P2T (Place, Transition) {
+        weight : Natural
+    }
+    Association T2P (Transition, Place) {
+        weight : Natural
+    }
+}
+
+PetriNets my_petrinet {
+    Place p1 {
+        tokens = 1
+    }
+    Place p2 {
+        tokens = 3
+    }
+    Transition t1 {}
+    P2T (p1, t1) {
+        weight = 1
+    }
+    T2P (t1, p2) {
+        weight = 2
+    }
+}
+
+export my_petrinet to models/my_petrinet

+ 22 - 0
integration/test_constructors_models_compiled.py

@@ -55,3 +55,25 @@ class TestConstructorsModelsCompiled(unittest.TestCase):
                    conformance_check("models/my_petrinet") + \
                    ['"return"', 'false']
         self.assertTrue(run_barebone(commands, ["OK"], 1))
+
+    def test_constructors_petrinets_constraints(self):
+        commands = ['"model"' ,'"initialize_SCD"', '"models/SimpleClassDiagrams"', '"exit"'] + \
+                   model_compile("integration/code/petrinets_constraints.mvc") + \
+                   conformance_check("models/PetriNets") + \
+                   ['"return"', 'false']
+        self.assertTrue(run_barebone(commands, ["OK"], 1))
+
+    def test_constructors_petrinet_instance_constraints(self):
+        commands = ['"model"' ,'"initialize_SCD"', '"models/SimpleClassDiagrams"', '"exit"'] + \
+                   model_compile("integration/code/petrinets_constraints.mvc") + \
+                   model_compile("integration/code/my_petrinet.mvc") + \
+                   conformance_check("models/my_petrinet") + \
+                   ['"return"', 'false']
+        self.assertTrue(run_barebone(commands, ["OK"], 1))
+
+    def test_constructors_petrinet_full_constraints(self):
+        commands = ['"model"' ,'"initialize_SCD"', '"models/SimpleClassDiagrams"', '"exit"'] + \
+                   model_compile("integration/code/my_petrinet_with_MM_and_constraints.mvc") + \
+                   conformance_check("models/my_petrinet") + \
+                   ['"return"', 'false']
+        self.assertTrue(run_barebone(commands, ["OK"], 1))

+ 6 - 3
interface/HUTN/grammars/modelling.g

@@ -1,8 +1,9 @@
 grammar{
-    start: (import | export | model | NEWLINE)+;
+    start: (import | export | include_files | model | NEWLINE)+;
 
     import: IMPORT MV_URL AS MODEL_ID;
     export: EXPORT MODEL_ID TO MV_URL;
+    include_files: INCLUDE STRVALUE NEWLINE;
 
     model: MODEL_ID MODEL_ID NEWLINE? LCURLY NEWLINE? (model_element)* RCURLY;
 
@@ -13,7 +14,7 @@ grammar{
     model_attribute
         : (MODEL_ID COLON MODEL_ID NEWLINE?)
         | (MODEL_ID ASSIGN value NEWLINE?)
-        | (DOLLAR STRVALUE DOLLAR NEWLINE?);
+        | (DOLLAR ANYTHING_EXCEPT_DOLLAR DOLLAR NEWLINE?);
 
     value
         : DEC_NUMBER
@@ -36,7 +37,7 @@ grammar{
         TRUE: 'True';
         FALSE: 'False';
         ASSIGN: '=';
-        DOLLAR: '$';
+        DOLLAR: '\$';
         WS: '[ ]+' @Impl;
         COLON : ':';
         LPAR: '\(';
@@ -44,5 +45,7 @@ grammar{
         COMMA: ',';
         EXPORT: 'export';
         TO: 'to';
+        ANYTHING_EXCEPT_DOLLAR: '[^$]*';
+        INCLUDE: 'include';
     }
 }

+ 21 - 3
interface/HUTN/hutn_compiler/model_visitor.py

@@ -1,4 +1,5 @@
 from visitor import Visitor
+from compiler import main as do_compile
 
 def jsonstr(s):
     return '"%s"' % s
@@ -14,6 +15,7 @@ class ModelVisitor(Visitor):
         self.name_maps = {}
         self.current_model = None
         self.current_element = None
+        self.includes = []
 
     def dump(self):
         print(self.constructors)
@@ -31,6 +33,9 @@ class ModelVisitor(Visitor):
             self.visit(t)
         self.constructors.append('"exit"')
 
+    def visit_include_files(self, tree):
+        self.includes.append(tree.get_children("STRVALUE")[0].get_text())
+
     def visit_import(self, tree):
         url = tree.get_children("MV_URL")[0]
         target = tree.get_children("MODEL_ID")[0]
@@ -75,15 +80,28 @@ class ModelVisitor(Visitor):
     def visit_model_attribute(self, tree):
         children = tree.get_children("MODEL_ID")
         is_definition = bool(tree.get_children("COLON"))
+        is_constraint = bool(tree.get_children("DOLLAR"))
+        is_assign = bool(tree.get_children("ASSIGN"))
 
         if is_definition:
-            # is definition
             attr_name = children[0].get_text()
             attr_type = children[1].get_text()
             self.constructors.extend(['"instantiate_link"', jsonstr(self.current_model), jsonstr("Association"), jsonstr(self.current_element + "_" + attr_name), jsonstr(self.current_element), jsonstr(attr_type)])
             self.constructors.extend(['"instantiate_attribute"', jsonstr(self.current_model), jsonstr(self.current_element + "_" + attr_name), jsonstr("name"), jsonstr(attr_name)])
-        else:
-            # is assign
+        elif is_assign:
             attr_name = children[0].get_text()
             attr_value = tree.get_children("value")[0]
             self.constructors.extend(['"instantiate_attribute"', jsonstr(self.current_model), jsonstr(self.current_element), jsonstr(attr_name), jsonstr(attr_value.get_text()) if attr_value.head == "STRVALUE" else attr_value.get_text()])
+        elif is_constraint:
+            constraint = tree.get_children("ANYTHING_EXCEPT_DOLLAR")[0].get_text()
+            whitespaces = len(constraint) - len(constraint.lstrip())
+            constraint = "\n".join(["\t" + line[whitespaces-1:].replace("    ", "\t") for line in constraint.split("\n") if len(line.strip()) != 0])
+            constraint = "".join(["include %s\n" % i for i in self.includes]) + \
+                         "String function constraint(model : Element, element : String):\n" + \
+                         "\tElement self\n" + \
+                         '\tself = model["model"][element]\n' + \
+                         constraint + "\n"
+            with open(".constraint.alc", 'w') as f:
+                f.write(constraint)
+                f.flush()
+            self.constructors.extend(['"add_constraint"', jsonstr(self.current_model), jsonstr(self.current_element)] + do_compile(".constraint.alc", "interface/HUTN/grammars/actionlanguage.g", "CS"))

+ 27 - 0
interface/HUTN/test/modelling_language/code/petrinets_constraints.mvc

@@ -0,0 +1,27 @@
+import models/SimpleClassDiagrams as SCD
+include "primitives.alh"
+
+SCD PetriNets{
+    Class Natural {
+        $
+            if (bool_not(is_physical_int(self))):
+                return "Natural has no integer value"
+            elif (integer_lt(self, 0)):
+                return "Natural does not have a positive or zero value"
+            else:
+                return "OK"
+         $
+    }
+    Class Place{
+        tokens : Natural
+    }
+    Class Transition{}
+    Association P2T (Place, Transition) {
+        weight : Natural
+    }
+    Association T2P (Transition, Place) {
+        weight : Natural
+    }
+}
+
+export PetriNets to models/PetriNets

+ 4 - 0
interface/HUTN/test/modelling_language/test_compile.py

@@ -27,3 +27,7 @@ class TestCompile(unittest.TestCase):
 
     def test_PetriNetsBoth(self):
         compile_file(self, "my_petrinet_with_MM.mvc")
+
+    def test_PetriNets_constraints(self):
+        compile_file(self, "petrinets_constraints.mvc")
+