6 次代碼提交 6c41c83f4f ... 07edcc0a8e

作者 SHA1 備註 提交日期
  Joeri Exelmans 07edcc0a8e Merge remote-tracking branch 'github/development' into development 9 月之前
  Joeri Exelmans a95a99f722 Merge remote-tracking branch 'github/development' into development 9 月之前
  Inte Vleminckx 51b8bdb001 Add test for bytes type 9 月之前
  Joeri Exelmans e0136937b9 cleanup 9 月之前
  Inte Vleminckx 98f36c4cf0 Adding bytes as a type 9 月之前
  Inte Vleminckx 86cd7027f3 Adding bytes as a type 9 月之前

+ 8 - 0
api/od.py

@@ -5,6 +5,7 @@ from services.primitives.boolean_type import Boolean
 from services.primitives.integer_type import Integer
 from services.primitives.string_type import String
 from services.primitives.actioncode_type import ActionCode
+from services.primitives.bytes_type import Bytes
 from uuid import UUID
 from typing import Optional
 from util.timer import Timer
@@ -41,6 +42,7 @@ class ODAPI:
         self.create_integer_value = self.od.create_integer_value
         self.create_string_value = self.od.create_string_value
         self.create_actioncode_value = self.od.create_actioncode_value
+        self.create_bytes_value = self.od.create_bytes_value
 
         self.__recompute_mappings()
 
@@ -208,6 +210,8 @@ class ODAPI:
                 tgt = self.create_actioncode_value(name, value)
             else:
                 tgt = self.create_string_value(name, value)
+        elif isinstance(value, bytes):
+            tgt = self.create_bytes_value(name, value)
         else:
             raise Exception("Unimplemented type "+value)
         self.__recompute_mappings()
@@ -235,6 +239,10 @@ class ODAPI:
                 if to_overwrite_type != "String":
                     raise Exception(f"Cannot assign string value '{value}' to value of type {to_overwrite_type}.")
                 String(referred_model, self.state).create(value)
+        elif isinstance(value, bytes):
+            if to_overwrite_type != "Bytes":
+                raise Exception(f"Cannot assign bytes value '{value}' to value of type {to_overwrite_type}.")
+            Bytes(referred_model, self.state).create(value)
         else:
             raise Exception("Unimplemented type "+value)
 

+ 3 - 1
bootstrap/primitive.py

@@ -47,7 +47,7 @@ def bootstrap_constraint(class_node, type_name: str, python_type: str, scd_root:
     bottom.create_edge(constraint_node, scd_node, "Morphism")
     bottom.create_edge(constraint_link, scd_link, "Morphism")
     
-def bootstrap_primitive_types(scd_root, state, integer_type, boolean_type, float_type, string_type, type_type, actioncode_type):
+def bootstrap_primitive_types(scd_root, state, integer_type, boolean_type, float_type, string_type, type_type, actioncode_type, bytes_type):
     # Order is important: Integer must come first
     class_integer    = bootstrap_type("Integer",    scd_root, integer_type,    state)
     class_type       = bootstrap_type("Type",       scd_root, type_type,       state)
@@ -55,6 +55,7 @@ def bootstrap_primitive_types(scd_root, state, integer_type, boolean_type, float
     class_float      = bootstrap_type("Float",      scd_root, float_type,      state)
     class_string     = bootstrap_type("String",     scd_root, string_type,     state)
     class_actioncode = bootstrap_type("ActionCode", scd_root, actioncode_type, state)
+    class_bytes      = bootstrap_type("Bytes",      scd_root, bytes_type,      state)
 
     # Can only create constraints after ActionCode type has been created:
     bootstrap_constraint(class_integer,    "Integer",    "int",   scd_root, integer_type,    actioncode_type, state)
@@ -63,3 +64,4 @@ def bootstrap_primitive_types(scd_root, state, integer_type, boolean_type, float
     bootstrap_constraint(class_float,      "Float",      "float", scd_root, float_type,      actioncode_type, state)
     bootstrap_constraint(class_string,     "String",     "str",   scd_root, string_type,     actioncode_type, state)
     bootstrap_constraint(class_actioncode, "ActionCode", "str",   scd_root, actioncode_type, actioncode_type, state)
+    bootstrap_constraint(class_bytes,      "Bytes",      "bytes", scd_root, bytes_type,      actioncode_type, state)

+ 4 - 10
bootstrap/scd.py

@@ -2,15 +2,7 @@ from state.base import State, UUID
 from services.bottom.V0 import Bottom
 from services.primitives.boolean_type import Boolean
 from services.primitives.string_type import String
-from bootstrap.primitive import (
-    bootstrap_primitive_types
-    # bootstrap_boolean_type,
-    # bootstrap_float_type,
-    # bootstrap_integer_type,
-    # bootstrap_string_type,
-    # bootstrap_type_type,
-    # bootstrap_actioncode_type
-)
+from bootstrap.primitive import bootstrap_primitive_types
 
 
 def create_model_root(bottom: Bottom, model_name: str) -> UUID:
@@ -32,6 +24,7 @@ def bootstrap_scd(state: State) -> UUID:
     float_type_root = create_model_root(bottom, "Float")
     type_type_root = create_model_root(bottom, "Type")
     actioncode_type_root = create_model_root(bottom, "ActionCode")
+    bytes_type_root = create_model_root(bottom, "Bytes")
 
     # create MCL, without morphism links
 
@@ -132,7 +125,8 @@ def bootstrap_scd(state: State) -> UUID:
         float_type_root,
         string_type_root,
         type_type_root,
-        actioncode_type_root)
+        actioncode_type_root,
+        bytes_type_root)
     # bootstrap_integer_type(mcl_root, integer_type_root, integer_type_root, actioncode_type_root, state)
     # bootstrap_boolean_type(mcl_root, boolean_type_root, integer_type_root, actioncode_type_root, state)
     # bootstrap_float_type(mcl_root, float_type_root, integer_type_root, actioncode_type_root, state)

+ 5 - 0
concrete_syntax/common.py

@@ -16,6 +16,8 @@ def display_value(val: any, type_name: str, indentation=0, newline_character='\n
         return '"'+val+'"'.replace('\n', newline_character)
     elif type_name == "Integer" or type_name == "Boolean":
         return str(val)
+    elif type_name == "Bytes":
+        return val
     else:
         raise Exception("don't know how to display value" + type_name)
 
@@ -48,6 +50,9 @@ class TBase(Transformer):
     def CODE(self, token):
         return _Code(str(token[1:-1])) # strip the ``
 
+    def BYTES(self, token):
+        return (bytes(token[2:-1], "utf-8"), token.line)  # Strip b"" or b''
+
     def INDENTED_CODE(self, token):
         skip = 4 # strip the ``` and the following newline character
         space_count = 0

+ 8 - 1
concrete_syntax/textual_od/parser.py

@@ -21,6 +21,7 @@ literal: INT
        | STR
        | BOOL
        | CODE
+       | BYTES
        | INDENTED_CODE
 
 INT: /[0-9]+/
@@ -28,6 +29,8 @@ STR: /"[^"]*"/
    | /'[^']*'/
 BOOL: "True" | "False"
 CODE: /`[^`]*`/
+BYTES: /b"[^"]*"/
+      | /b'[^']*'/
 INDENTED_CODE: /```[^`]*```/
 
 type_name: IDENTIFIER
@@ -67,7 +70,7 @@ def parse_od(state,
 
     primitive_types = {
         type_name : UUID(state.read_value(state.read_dict(state.read_root(), type_name)))
-            for type_name in ["Integer", "String", "Boolean", "ActionCode"]
+            for type_name in ["Integer", "String", "Boolean", "ActionCode", "Bytes"]
     }
 
     class T(Transformer):
@@ -89,6 +92,10 @@ def parse_od(state,
         def CODE(self, token):
             return (_Code(str(token[1:-1])), token.line) # strip the ``
 
+        def BYTES(self, token):
+            # return (bytes(token[2:-1], "utf-8"), token.line)  # Strip b"" or b''
+            return (bytes(token[2:-1], "utf-8"), token.line)  # Strip b"" or b''
+
         def INDENTED_CODE(self, token):
             skip = 4 # strip the ``` and the following newline character
             space_count = 0

+ 1 - 1
concrete_syntax/textual_od/renderer.py

@@ -9,7 +9,7 @@ def render_od(state, m_id, mm_id, hide_names=True):
     
     m_od = od.OD(mm_id, m_id, state)
 
-    serialized = set(["Integer", "String", "Boolean", "ActionCode"]) # assume these types always already exist
+    serialized = set(["Integer", "String", "Boolean", "ActionCode", "Bytes"]) # assume these types always already exist
 
     def display_name(name: str):
         # object names that start with "__" are hidden

+ 10 - 0
services/od.py

@@ -5,6 +5,7 @@ from services.primitives.integer_type import Integer
 from services.primitives.string_type import String
 from services.primitives.boolean_type import Boolean
 from services.primitives.actioncode_type import ActionCode
+from services.primitives.bytes_type import Bytes
 from api.cd import CDAPI
 from typing import Optional
 
@@ -147,6 +148,13 @@ class OD:
         actioncode_t.create(value)
         return self.create_model_ref(name, "ActionCode", actioncode_node)
 
+    def create_bytes_value(self, name: str, value: str):
+        from services.primitives.bytes_type import Bytes
+        bytes_node = self.bottom.create_node()
+        bytes_t = Bytes(bytes_node, self.bottom.state)
+        bytes_t.create(value)
+        return self.create_model_ref(name, "Bytes", bytes_node)
+
     # Identical to the same SCD method:
     def create_model_ref(self, name: str, type_name: str, model: UUID):
         # create element + morphism links
@@ -389,6 +397,8 @@ def read_primitive_value(bottom, modelref: UUID, mm: UUID):
         return Boolean(referred_model, bottom.state).read(), typ_name
     elif typ_name == "ActionCode":
         return ActionCode(referred_model, bottom.state).read(), typ_name
+    elif typ_name == "Bytes":
+        return Bytes(referred_model, bottom.state).read(), typ_name
     else:
         raise Exception("Unimplemented type:", typ_name)
 

+ 24 - 0
services/primitives/bytes_type.py

@@ -0,0 +1,24 @@
+from uuid import UUID
+from state.base import State
+from services.bottom.V0 import Bottom
+
+
+class Bytes:
+    def __init__(self, model: UUID, state: State):
+        self.model = model
+        self.bottom = Bottom(state)
+        type_model_id_node, = self.bottom.read_outgoing_elements(state.read_root(), "Bytes")
+        self.type_model = UUID(self.bottom.read_value(type_model_id_node))
+
+    def create(self, value: bool):
+        if "bytes" in self.bottom.read_keys(self.model):
+            instance, = self.bottom.read_outgoing_elements(self.model, "bytes")
+            self.bottom.delete_element(instance)
+        _instance = self.bottom.create_node(value)
+        self.bottom.create_edge(self.model, _instance, "bytes")
+        _type, = self.bottom.read_outgoing_elements(self.type_model, "Bytes")
+        self.bottom.create_edge(_instance, _type, "Morphism")
+
+    def read(self):
+        instance, = self.bottom.read_outgoing_elements(self.model, "bytes")
+        return self.bottom.read_value(instance)

+ 3 - 2
state/base.py

@@ -2,13 +2,14 @@ from abc import ABC, abstractmethod
 from typing import Any, List, Tuple, Optional, Union
 from uuid import UUID, uuid4
 
-primitive_types = (int, float, str, bool)
+primitive_types = (int, float, str, bool, bytes)
 INTEGER = ("Integer",)
 FLOAT = ("Float",)
 STRING = ("String",)
 BOOLEAN = ("Boolean",)
 TYPE = ("Type",)
-type_values = (INTEGER, FLOAT, STRING, BOOLEAN, TYPE)
+BYTES = ("Bytes",)
+type_values = (INTEGER, FLOAT, STRING, BOOLEAN, TYPE, BYTES)
 
 
 Node = UUID

+ 9 - 0
state/test/test_create_nodevalue.py

@@ -171,3 +171,12 @@ def test_create_nodevalue_string_type(state):
 def test_create_nodevalue_invalid_type(state):
     id1 = state.create_nodevalue(("Class",))
     assert id1 == None
+
+
+@pytest.mark.usefixtures("state")
+def test_create_nodevalue_bytes_type(state):
+    id1 = state.create_nodevalue(("Bytes",))
+    assert id1 != None
+
+    v = state.read_value(id1)
+    assert v == ("Bytes",)

+ 2 - 2
transformation/merger.py

@@ -4,7 +4,7 @@ from concrete_syntax.textual_od import parser, renderer
 from services.scd import SCD
 from util.timer import Timer
 
-PRIMITIVE_TYPES = set(["Integer", "String", "Boolean", "ActionCode"])
+PRIMITIVE_TYPES = set(["Integer", "String", "Boolean", "ActionCode", "Bytes"])
 
 # Merges N models. The models must have the same meta-model.
 # Care should be taken to avoid naming collisions before calling this function.
@@ -12,7 +12,7 @@ def merge_models(state, mm, models: list[UUID]):
     with Timer("merge_models"):
         primitive_types = {
             type_name : UUID(state.read_value(state.read_dict(state.read_root(), type_name)))
-                for type_name in ["Integer", "String", "Boolean", "ActionCode"]
+                for type_name in ["Integer", "String", "Boolean", "ActionCode", "Bytes"]
         }
 
         merged = state.create_node()