Skip to content

Instantly share code, notes, and snippets.

@aranega
Last active May 3, 2024 02:04
Show Gist options
  • Save aranega/b7ac11ca2554385ea4896545f6b5de0d to your computer and use it in GitHub Desktop.
Save aranega/b7ac11ca2554385ea4896545f6b5de0d to your computer and use it in GitHub Desktop.
Micro reflexive MDE-like kernel in Python
class MList(object):
def __init__(self, owner, feature):
self.innerlist = []
self.owner = owner
self.feature = feature
def size(self):
return len(self.innerlist)
def append(self, value, update_opposite=True):
if self.feature.get('composite'):
value.container = self.owner
self.innerlist.append(value)
opposite = self.feature.get('opposite')
if update_opposite and opposite:
if opposite.get('upper') < 0:
value.get(opposite.get('name')).append(self.owner, update_opposite=False)
else:
value.set(opposite.get('name'), self.owner, update_opposite=False)
def extend(self, iterable, update_opposite=True):
if self.feature.get('composite'):
for value in iterable:
value.container = self.owner
opposite = self.feature.get('opposite')
if update_opposite and opposite:
if opposite.get('upper') < 0:
value.get(opposite.get('name')).append(self.owner, update_opposite=False)
else:
value.set(opposite.get('name'), self.owner, update_opposite=False)
self.innerlist.extend(iterable)
def remove(self, value, update_opposite=True):
try:
self.innerlist.remove(value)
if self.feature.get('composite'):
value.container = None
opposite = self.feature.get('opposite')
if update_opposite and opposite:
if opposite.get('upper') < 0:
value.get(opposite.get('name')).remove(self.owner, update_opposite=False)
else:
value.set(opposite.get('name'), self.owner, update_opposite=False)
except Exception:
raise
def __iter__(self):
return iter(self.innerlist)
def __getitem__(self, index):
return self.innerlist[index]
def __repr__(self):
return repr(self.innerlist)
class MObject(object):
def __init__(self, metaclass=None):
self.mclass = metaclass
self.container = None
self.values = {}
def withValues(self, vals):
self.values.update(vals)
return self
def new(self, **kwargs):
instance = self.__class__(self)
for k, v in kwargs.items():
instance.set(k, v)
## init trick
if k == 'opposite':
v.set('opposite', instance, update_opposite=False)
return instance
def get(self, name):
try:
return self.values[name]
except KeyError:
all_superclasses = self.mclass.all_inheritance()
features = {feature.get('name'): feature for superclass in all_superclasses for feature in superclass.get('features')}
if name not in features:
raise Exception(f"Feature {name} does not exist for {self.mclass.get('name')}")
feature = features[name]
if feature.get('upper') < 0:
self.values[name] = MList(self, feature)
else:
self.values[name] = feature.get('default')
return self.values[name]
def set(self, name, value, update_opposite=True):
all_superclasses = self.mclass.all_inheritance()
features = {feature.get('name'): feature for superclass in all_superclasses for feature in superclass.get('features')}
if name not in features:
raise Exception(f"Feature {name} does not exist for {self.mclass.get('name')}")
feature = features[name]
if feature.get('composite'):
value.container = self
self.values[name] = value
opposite = feature.get('opposite')
if update_opposite and opposite:
if opposite.get('upper') < 0:
value.get(opposite.get('name')).append(self, update_opposite=False)
else:
value.set(opposite.get('name'), self, update_opposite=False)
def all_inheritance(self):
res = [self]
for superclass in self.get('superclasses'):
res.extend(superclass.all_inheritance())
return res
def instanceof(self, other):
if self.mclass is other:
return True
all_superclasses = self.mclass.all_inheritance()
return other in all_superclasses
## Create M3 level
M3Class = MObject()
M3Class.mclass = M3Class
M3Property = MObject(M3Class)
M3Property.values.update({
'name': 'M3Property',
'superclasses': [],
'features': [
MObject(M3Property).withValues({
'name': 'name',
'type': str,
'upper': 1,
'composite': False,
'default': None,
'opposite': None,
}),
MObject(M3Property).withValues({
'name': 'type',
'type': M3Class,
'upper': 1,
'composite': False,
'default': None,
'opposite': None,
}),
MObject(M3Property).withValues({
'name': 'upper',
'type': int,
'upper': 1,
'composite': False,
'default': 1,
'opposite': None,
}),
MObject(M3Property).withValues({
'name': 'composite',
'type': bool,
'upper': 1,
'composite': False,
'default': False,
'opposite': None,
}),
MObject(M3Property).withValues({
'name': 'default',
'type': object,
'upper': 1,
'composite': False,
'default': None,
'opposite': None,
}),
MObject(M3Property).withValues({
'name': 'opposite',
'type': M3Property,
'upper': 1,
'composite': False,
'default': None,
'opposite': None,
}),
]
})
M3Class.values.update({
'name': 'M3Class',
'superclasses': [],
'features': [
MObject(M3Property).withValues({
'name': 'name',
'type': str,
'upper': 1,
'composite': False,
'default': None,
'opposite': None,
}),
MObject(M3Property).withValues({
'name': 'features',
'type': M3Property,
'upper': -1,
'composite': True,
'default': None,
'opposite': None,
}),
MObject(M3Property).withValues({
'name': 'abstract',
'type': bool,
'upper': 1,
'composite': False,
'default': False,
'opposite': None,
}),
MObject(M3Property).withValues({
'name': 'superclasses',
'type': M3Class,
'upper': -1,
'composite': False,
'default': False,
'opposite': None,
}),
]
})
## Usage example
## Creating a M2 model (metamodel)
NamedElement = M3Class.new(name='NamedElement')
NamedElement.get('features').append(
M3Property.new(name='name', type=str)
)
Repository = M3Class.new(name='Repository')
Commit = M3Class.new(name='Commit')
Repository.get('superclasses').append(NamedElement)
Commit.get('superclasses').append(NamedElement)
commitsFeature = M3Property.new(name='commits', type=Commit, upper=-1, composite=True)
Repository.get('features').extend((
M3Property.new(name='url', type=str),
commitsFeature
))
Commit.get('features').extend((
M3Property.new(name='repository', type=Repository, opposite=commitsFeature),
))
## Creating M1 model instance of the defined M2 metamodel
r1 = Repository.new(url='http://github.com/stuff/truc', name='truc')
r1.get('commits').append(Commit.new(name='MYCOMMIT'))
print(commitsFeature.get('opposite'))
print(r1.get('commits')[0].get('name'))
print(r1.instanceof(NamedElement))
print(r1.get('commits'))
print(r1.get('commits')[0].get('repository'))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment