Compare commits

..

6 commits

Author SHA1 Message Date
07edcc0a8e Merge remote-tracking branch 'github/development' into development 2025-02-05 16:27:01 +01:00
a95a99f722 Merge remote-tracking branch 'github/development' into development 2025-02-05 16:26:37 +01:00
Inte Vleminckx
51b8bdb001 Add test for bytes type 2025-02-05 16:26:30 +01:00
e0136937b9 cleanup 2025-02-05 16:26:22 +01:00
Inte Vleminckx
98f36c4cf0 Adding bytes as a type 2025-02-05 16:24:22 +01:00
Inte Vleminckx
86cd7027f3 Adding bytes as a type 2025-02-05 16:01:56 +01:00
11 changed files with 77 additions and 17 deletions

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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",)

View file

@ -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()