A package is a collection of data types, functions and other objects which logically belong together. All mathematical functionality of the sygnm framework is implemented in packages. Packages are loaded once, at initialization. It is not possible to unload packages as this could easily lead to an inconsistent state.
All packages have the following attributes:
- Name (uniquely identifies the package)
- Version number
- Name and e-mail of author
- Dependencies (what other packages are needed to use this package?)
- Conflicts (what other packages can't be used together with this package?)
- Initialization and deinitialization methods (to acquire and free global resources needed by the package)
- Hash method (returns a hash value unique to the current instance of the package, dependent on the exact version of external dependencies and other factors)
A package can contain:
- Data types
- Typeclasses (abstract "interfaces" which can be implemented by data types)
- Typeclass implementations (implementations of typeclass "interfaces")
- Tree transformations (special functions which transform mathematical expressions during evaluation)
- Parsers (converts text or other input formats to mathematical expressions)
- Renderers (converts mathematical expression to text or other output formats)
- I/O interfaces (handles communication between the sygnm framework and the outside world)
- Rewrite rules (rules to transform mathematical expressions)
All objects of the sygnm system must have a unique identifier. An identifier is either "simple" or "compound". Simple identifiers are strings. Compound identifiers have three parts, all of which are strings. The parts of a compound identifier are: package name, name and variant name. Function and data type identifiers are compound, while all other identifiers are simple. Compound identifiers can be incomplete when one or more parts do not have a value. Such identifiers identify a set of objects instead of a single one.
Packages are implemented as shared libraries written using (a subset of) the C++ language.
The contents of a package is descripted in the "package descriptor" file (extension
This file uses a very simple a simple key-value format and can also contain C++ snippets.
A code generator (called
sygnm-codegen) then reads the package descriptor file and generates all necessary
headers and boilerplate code. Implementation stubs are also generated, which means that the user only needs to fill out
empty function bodies, all other code is handled by the code generator. Bindings for other languages (currently Python) are also automatically generated from the package descriptor file.
If the list of all required packages is known before compiling the sygnm framework (e.g. when the sygnm framework is used as a static library linked into other software), then it is possible to statically compile the sygnm framework core and the required packages into a single file (which means that no I/O operations are necessary when initializing the sygnm system). It is also possible to disable all external logging and other output, so that the sygnm framework truly behaves as a simple library and does not interfere with its host software.
- ^ Uniqueness is required only among objects of the same type (e.g. it is possible to have data types and functions or parsers and renderers with the same ID).
- ^ An identifier always belongs to a class, not an instance of a class. This means that objects which are instances of the same class have the same identifier.