-
Notifications
You must be signed in to change notification settings - Fork 0
CreatingBackend
Relevant as of version 1.0.0
π This article will describe the algorithm for implementing your own backend for Mess, using "MyLangBackend" as an exampleβa backend for "MyLang."
---
title: Relationships Between Backend Components
---
graph TD;
backend.py:MyLangBackend-- Creating a Message ---> mylang.py{{Is message implemented in messages/mylang.py}}
backend.py:MyLangBackend-- Rendering a Message ---> mylang.py
mylang.py --> |Yes| messages/mylang.py
mylang.py --> |No| messages/base.py
messages/base.py-- Rendering a Message --> d(NotImplementedException)
messages/mylang.py-- Mangling -->backend.py:MyLangBackend;
messages/mylang.py-- Rendering a Message -->templates/mylang/*.j2;
templates/mylang/*.j2-- Retrieving Message Information -->messages/mylang.py;
Our backend class, inheriting from Backend, should be declared in backend.py
below all previously declared classes. This is necessary for the correct functioning of the automatic search for implemented backends.
π As of now (version 1.0.0), backend search occurs in
mess.py
. In future versions, this will be changed and moved to a separate file.
So, let's add this code to the end of the backend.py
file:
class MyLangBackend(Backend):
# Backend code
name = "mylang"
# Template directory name
path_to_templates = "mylang/"
def render_message(self, message: messages_base.Message):
return super().render_message(message)
Here, we create the MyLangBackend
class, inheriting from Backend
, and define the values for its default fields.
The name
field defines the addressable name of the backend, which is used when selecting backends when the user runs the mess.py <name> <out> <in>
generation script.
The path_to_templates
field specifies the location of the backend's template files. This path is constructed as /templates/<path_to_templates>
, so in this case: /templates/mylang/
.
π In this example, the
MyLangBackend::render_message
method is deliberately left in, although it could be omitted here. This was done to show that there is an opportunity to override the default algorithm instead (see the graph above).
π A full description of the base class
Backend
can be found here or in theBackend.py
file.
The backend creates instances of the necessary messages, first built-in, then user-defined (from the ini file). For creation, it uses either the message implementation from messages/base.py
or, if available, from messages/mylang.py
.
π This was done so that when a new message is added to
base.py
, and it does not yet have an implementation in the current backend, and it is used in the user's description, aNotImplementedException
is thrown, allowing immediate identification of such a message.
In the /messages/
directory, create a mylang.py
file where all messages from base.py
are implemented. The main task here is to override the base.Message::render
and base.Message::get_render_template
methods, where the exception is thrown.
π A list of all built-in messages registered in Mess can be found here or in the
messages/base.py
file.
Here is an example of such a message (taken from imhex.py
):
class Message(base.Message):
def __init__(self, name=None, fields=None, generic_args=None, docs=None):
super().__init__(name, fields, generic_args, docs)
def render(self, backend: 'Backend'):
return backend.get_template(self.get_render_template()) \
.render(data={'message': self, 'backend': backend})
def get_render_template(self) -> str:
return "Type.j2"
Here, the mylang.Message::get_render_template
method is overridden to simply return the template name, as well as the mylang.Message::render
method.
In the mylang.Message::render
method, the template is retrieved and rendered by passing data
.
π To implement your own backend, it is best to copy
base.py
and implement the messages there, or usecpp.py
, which already includes template work.
There is great potential here to change input parameters, depending on what the template accepts.
π Here's where things get really interesting! This is where the rendered result's appearance is defined.
In the /templates/mylang/
directory, create a Type.j2
file with the following content (taken from templates/imhex/Type.j2
):
{% set msg = message %}
{# First simple fields (non-variative), then complex, variative #}
{% set sorted_fields = msg.fields | sort(attribute="message.is_variative") %}
struct {{ msg | message_type }} {
{% for field in sorted_fields %}
{{ field | field_type }} {{ field | field_name }};
{% endfor %}
};
π The template is greatly simplified for better understanding (for example, it lacks support for comments, protocol hashing). Full, real examples can be found in
/templates/
.
This template implements a structure with a mangled message name using the message_type
filter and the fields of this message.
π A full list of filters can be found here or in the
filters.py
file.
--
In the end, I hope I have managed to at least roughly explain how to implement your own backend. This article and all others will be gradually updated to make Mess more understandable for everyone πββοΈ
π If you have any questions, feel free to ask them in the Discussions or Issues of the Mess repository on Github. Suggestions and PRs are also welcome!
Back to: Home | Implementing Your Own Backend