Time of page creation
Time of the last page update

DRAFT: Kueea Module Declaration Language

This document is a live working draft. Do not implement.

KMDL documents declare one Kueea Module per document. Their syntax is designed to be human-readable and fairly easy to read and write using the most simple text editors.

KMDL processors take KMDL documents as input. The primary output are source files in a given programming language. Other output include module documentation in HTML or other formats. They are part of tool chains that build Kueea Module implementations.

This document defines version 0 of the the language.

Keywords

The key words ‘MUST,’ ‘MUST NOT,’ ‘REQUIRED,’ ‘SHALL,’ ‘SHALL NOT,’ ‘SHOULD,’ ‘SHOULD NOT,’ ‘RECOMMENDED,’ ‘NOT RECOMMENDED,’ ‘MAY,’ and ‘OPTIONAL’ in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.

Overview

Processing a KMDL document produces a tree of items.

The root of the tree is the module item. Items declared in the document are its children: classes, data objects and functions.

An item is a set of variables. Variables of an item are referenced in prose like this: item.variable (using a dot separator).

Each item is associated with the module level at which it is declared. Higher module levels include all items declared at lower levels.

Items have an associated human-readable textual description. This text is treated as opaque data by a KMDL processor. It is only considered when generating output for human users.

Syntax

A KMDL document is a sequence of Unicode characters. The encoding of the document MUST be UTF-8.

Lines are sequences of characters separated by a sequence of two characters: U+000D CARRIAGE RETURN and U+000A LINE FEED.

Whitespace is either U+0020 SPACE or U+0009 HORIZONTAL TAB.

The documents are read and processed line by line. Maximum length of a line is 1024 code units, including the line separator.

There are three kinds of lines: processor instructions, item descriptions, and comments.

Comments

Comments are lines that are read and discarded. There are two kinds of comments.

One-line comments are lines beginning with optional whitespace followed by no more than one consecutive U+0023 NUMBER SIGN character.

# This is a one-line comment.
  # This is a one-line comment.
THIS IS NOT A COMMENT.
# # # This is a one-line comment.

Multi-line comments begin and end with a line beginning with optional whitespace followed by 2 consecutive U+0023 NUMBER SIGN characters.

## This is the first line of a multi-line comment.
This is a comment.
.This is a comment.
# # This is inside a multi-line comment.
  ## This is the last line of a multi-line comment.
THIS IS NOT A COMMENT.

Instructions

Instructions declare items and change processor state. These lines begin with optional whitespace followed by one U+002E FULL STOP character and the instruction name. Instruction arguments, each preceeded by whitespace. follow the name.

Instruction names are case-sensitive. They MUST be written with small letters and are four-character long.

.inst arg1 arg2
   .inst arg1

Item descriptions

Any other line is text - a human-readable textual description of the currently active item.

These lines are passed as input to another program when generating module documentation or are ignored if the information is unneeded.

Their syntax is out of scope of this document.

.item example1
Description of the example1 item.

Description of the example1 item.

.item example2

Description of the example2 item.

Line indentation

The preceeding whitespace on an instruction line sets the amount of ignored preceeding whitespace for the text lines that come after it.

Both of the whitespace characters count as one.

Consider the following example:

   .inst first
   Line 1-1.
     Line 1-2.
  Line 1-3.
.inst second
   Line 2-1.
     Line 2-2.
Line 2-3.

The first line is an instruction indented by 3 whitespace characters. The ignored indentation becomes 3.

The second line is text indented by 3 whitespace characters. The parser removes the first 3 whitespace characters. The resulting line has no preceeding whitespace characters.

The third line is text indented by 5 whitespace characters. The parser removes the first 3 whitespace characters. The resulting line has 2 preceeding whitespace characters.

The fourth line is text indented by 2 whitespace characters. The parser removes the first 3 whitespace characters. In this case, the line has less whitespace, so all is removed. The resulting line has 0 preceeding whitespace characters.

The item description for the first item is thus:

Line 1-1.
  Line 1-2.
Line 1-3.

The fifth line is an instruction indented by 0 whitespace characters. The ignored indentation becomes 0.

The sixth line is text indented by 3 whitespace characters. The parser removes the first 0 whitespace characters. The resulting line has 3 preceeding whitespace characters.

The seventh line is text indented by 5 whitespace characters. The parser removes the first 0 whitespace characters. The resulting line has 5 preceeding whitespace characters.

The eigth line is text indented by 0 whitespace characters. The parser removes the first 0 whitespace characters. The resulting line has 0 preceeding whitespace characters.

The item description for the second item is thus:

   Line 2-1.
     Line 2-2.
Line 2-3.

ABNF (formal syntax)

The following KMDL rule expresses the syntax in ABNF.

KMDL  = docv CRLF *( line CRLF )
docv  = %s".kmdl" SP 1*4DIGIT
line  = comm / inst / text

comm  = cmul / cone
cmul  = *WSP "##" *OCTET CRLF *WSP "##" *OCTET
cone  = *WSP  "#" *OCTET

inst  = *WSP  "." *( WSP / VCHAR )
text  = [ *WSP "\" ] *OCTET

ABNF rules are referenced in prose like this: <rule>.

The first non-whitespace character of <text> MAY be a U+005C REVERSE SOLIDUS. If so, the \ character is removed before further processing of the line. This is an escape mechanism in case the line begins with # or ..

Non-items

This section defines objects that are not items.

Containers

Some objects are stored in a container object.

A list is an ordered container, which means that position of elements in a list is significant.

A set is an unordered container.

Class identifier

Classes are identified by 128-bit values. These values are globally unique and are treated as opaque data.

It is expected that the value is a Universally Unique Identifier. The value MAY NOT be a valid UUID, although it SHOULD be.

The nil UUID value is reserved and means no value.

Modules and interfaces are special kind of classes.

Class level

Classes have levels.

A level is a 16-bit unsigned integer.

Class of a given level includes every member declared at all of its lower levels.

Symbol identifier

Some items have an associated symbol identifier.

A symbol identifier is a 64-bit unsigned integer.

There MUST NOT be two symbol identifiers of the same value within a module.

By default, the value is the result of passing a character string to the 64-bit FNV-1a (Fowler-Noll-Vo) hash function:

hash = 0xCBF29CE484222325
for each octet_of_data to be hashed
  hash = hash XOR octet_of_data
  hash = hash * 0x100000001B3
return hash

Symbol identifiers should only be explicitly declared in case of a collision. The encoding of the string is the same as for the document - UTF-8.

The hashed string consists of names of items separated by a U+0024 DOLLAR SIGN character.

Examples:

Input stringOutput value
global_object0x8EAE284DFC37BA58
iface$function0x59976F93E8833DA3
class$0000$function0x713BC2D41B847A6F

Tag

A tag is a sequence of characters.

The minimum length of the sequence is 1.

The maximum length of the sequence is 16.

Tags are stored in sets.

Name

Some items have an associated name.

A name is a sequence of characters.

The minimum length of the sequence is 1.

The maximum length of the sequence is 64.

Item reference

An item reference is a list of names.

The first name is special in that it might be a module (class) identifier instead.

Register types and classes

A class can be assigned a register type. Such class becomes a register class.

These classes are special in that they have a pre-defined interface for transferring values from a CPU register to an object and vice-versa.

These functions are needed because the order of octets in memory might be different from the byte order the CPU expects.

For example, consider a class called u32 occupying 4 octets in memory. We then declare that there is a function for loading a value from an instance of this class into a 32-bit-wide CPU register, which then can be used to perform integer arithmetic on the value.

Otherwise, there is no mapping between CPU registers and object data. The data is seen as nothing more than an array of opaque octets.

The set of possible register types and their values is predefined.

Memory alignment

An alignment is a 32-bit unsigned integer that is a power of 2. The value 0 means undefined.

Padding is inserted before a data member if the resulting memory address would not be divisible by its alignment.

A default alignment of a class is the highest alignment of its data members.

Authors must consider alignment and padding when designing classes.

Object type

An object type is a tuple of:

  • item reference to a class,
  • level of the referenced class,
  • type of handle.

There are eight predefined classes, which are always at level 0. All other types are classes declared by modules.

An octet is 8 bits with no associated meaning. Its register type is an 8-bit unsigned integer. This is the fundamental type - all objects are arrays of octets.

A boolean occupies 1 octet. Its register type is an unsiged integer of at least 1 bits. It is mappped to an unsigned 8-bit integer in practice. Possible values are: true (non-zero) and false (zero).

A status is a boolean with a specific meaning. It is used as the return value of functions. False means that there is nothing to report (success). True means that the task's status stack was pushed onto - the caller should examine the stack before continuing.

A cmprval occupies 1 octet. Its register type is a signed integer of at least 2 bits. It is mappped to a signed 8-bit integer in practice. Possible values are: 0 means equal, 1 or more means more than, -1 means a comparision error and -2 or less means less than. Simply put, one first tests for -1 (error) and then compares with 0. Functions that return this object also set the CPU flags accordingly, so that a conditional jump may immediately follow the function call.

An objsize occupies 4 octets aligned to 4 octets. Octets are ordered in increasing order of significance. Its register type is a 32-bit unsigned integer.

An address occupies 8 octets aligned to 8 octets. Octets are ordered in increasing order of significance. Its register type is a 64-bit unsigned integer.

An id16 occupies 16 octets aligned to 8 octets. It is an array of 16 octets. It has no register type.

A handle occupies 32 octets aligned to 8 octets. It is a structure defined as follows:

.cbeg handle
.data address address[8]
.data id16    node_id
.data octet   nonce[8]

Its register type is a (CPU-defined) memory reference.

Handles are specified as access rights and a class of referenced object. Access rights (to object data in memory) are one of:

none
No access rights. Use to avoid duplicated rights.
read
Read rights.
rdex
Read and execute rights.
rdwr
Read and write rights.
rwex
Read, write and execute rights.

The system gives access as many times as there are handles in a class. A class only needs to have one handle with specific rights to an object. Other handles to the same object SHOULD be of the no-access type in order to avoid unnecessary computations when passing objects around.

Array length

Representation of an array length MUST consist of at least:

  • var: reference to the member storing the amount of elements,
  • min: minimum amount of elements,
  • max: maximum amount of elements.

Amount of elements is a 32-bit unsigned integer.

An invalid array length is one of which either:

  • max is equal to or more than 232.
  • min is equal to or more than 232.
  • min is more than max.

The min and max values are used in calculation of the minimum length and the possible maximum length of a class instance.

The member referenced by var MUST be an instance of a register class with an unsigned integer register type. This member MUST have a lower address than the array.

If var is not empty, then addresses of all subsequent members are calculated at runtime. Otherwise, if min and max are not equal, the array MUST be the last data member of the class.

Value override

Representation of a value override MUST consist of at least:

  • mlv: associated module level,
  • clv: associated class level,
  • member: item reference to a descriptor's data member,
  • value: value.

Value

Representation of a value is implementation-dependent.

Consult the definition of the <VAL> rule for more information.

Items

All items contain a text variable, which is a list of objects which MUST consist of at least:

  • data: opqaue buffer; textual data,
  • format: name; format of the data.

When appending a new object n to text, where o is the last object in text: if n.format equals to o.format, data in n.data MAY be appended to o.data with a preceeding line separator instead of appending a new object.

Module

Representation of a module MUST consist of at least:

  • mid: the module's (class) identifier,
  • mlv: the module's (class) level,
  • desc: list of data members (descriptor),
  • data: list of data members (instance),
  • func: set of function members,
  • nval: set of named values,
  • nref: set of named references,
  • types: set of classes,
  • mrefs: set of external module references, tuples of: name (alias), module identifier and target module level.

Class

Representation of a class MUST consist of at least:

  • cid: class identifier,
  • clv: current class level,
  • regt: register type,
  • desc: list of data members (descriptor),
  • data: list of data members (instance),
  • func: set of function members,
  • nval: set of named values,
  • nref: set of named references,
  • ival: list of value overrides,
  • tags: set of tags,
  • name: name of the class.

Data member

Representation of a data member MUST consist of at least:

  • mlv: associated module level,
  • clv: associated class level,
  • sid: symbol identifier,
  • tags: set of tags,
  • type: type reference,
  • alen: array length,
  • align: memory alignment,
  • value: default value (if type is a register class),
  • name: name of the object.

Function member

Representation of a function member MUST consist of at least:

  • mlv: module level,
  • clv: class level,
  • sid: symbol identifier,
  • tags: set of tags,
  • params: list of function parameters,
  • rval: type of the function's return value,
  • name: name of the function.

Function parameter

Representation of a function parameter MUST consist of at least:

  • itype: input type reference,
  • otype: output type reference,
  • name: parameter name.

Function return value

Representation of a return value MUST consist of at least:

  • type: type reference.

Named value

Representation of a named value MUST consist of at least:

  • mlv: associated module level,
  • clv: associated class level,
  • value: value,
  • name: name of the value.

Named reference

Representation of a named reference MUST consist of at least:

  • mlv: associated module level,
  • clv: associated class level,
  • iref: item reference,
  • name: name of the reference.

Parser

A KMDL parser consists of a line parser, an instruction parser and the functions the latter invokes.

Both the line parser and the functions have access to a shared state in addition to their own, private state.

Shared state

Shared state of the parser consists of the following variables:

  • mset: set of modules,
  • mbeg: object reference to the current module,
  • text: object reference to the current item description,
  • format: name of the current text format.

When an object reference is nothing, it means that the reference is set to a value that does not reference any objects.

Loading algorithm

The processor loads a module using the following algorithm.

The function takes 3 parameters: a module identifier, a module level and an external function for fetching KMDL documents. These are mentioned in steps 1-3.

  1. Let mid be the identifier of the loaded module.
  2. Let mlv be the target level of the loaded module.
  3. Let fetch be the extenal fetcher.
  4. Search mset for a module m with m.mid equal to mid.
  5. If found and m.mlv is no less than mlv, return success.
  6. If found and m.mlv is less than mlv, remove m from mset.
  7. Obtain an octet stream doc by calling fetch, passing mid and mlv as arguments.
  8. If fetch has failed, return failure.
  9. Set mbeg to a newly created module representation.
  10. Set mbeg.mid to mid.
  11. Set text to nothing,
  12. Set format to markdown.
  13. Invoke the line parser on doc.
  14. If the parser failed, delete mbeg and return failure.
  15. If the mbeg.mlv is less than mlv, delete mbeg and return failure.
  16. Insert mbeg into mset.
  17. Iterate mbeg.mrefs and recursively call this algorithm with the arguments from the tuple; if any of the referenced modules failed to load, return failure.
  18. Return success.

Line parser

State of the line parser consists of the following variables:

  • line: current line (Unicode string),
  • wslv: current line indentation (integer),
  • skip: ignored line indentation (ingeter).

The line parser takes a stream of octets as input. It loads lines and processes them until the end of the stream.

The parser loads a line as follows:

  1. Let cr be a boolean.
  2. Let input be the input stream of octets.
  3. Set line to an empty string.
  4. Set cr to false.
  5. While input is not empty:
    1. Decode the next character c from input.
    2. If line is longer than 1024 characters, return failure.
    3. Append c to line.
    4. If cr is true and c is U+000A LINE FEED, remove the last character in line and return success.
    5. If c is U+000D CARRIAGE RETURN, set cr to true; otherwise, set cr to false.
  6. Return success.

After each line is loaded, it is processed. The first line has special processing.

The first line

docv  = %s".kmdl" SP 1*4DIGIT

If line does not exactly match the <docv> rule above, the line parser MUST return failure and load no further lines.

The DIGITs encode the version of a KMDL processor as a decimal integer. If the version is higher (more) than the implemented one, the line parser MUST return failure and load no further lines.

This document defines version 0.

Other lines

The parser counts the amount of whitespace at the beginning of line and stores the resulting value in wslv.

Further processing depends on the first character after the whitespace.

If the line is a one-line comment, the line is ignored.

If the line is a multi-line comment, the parser loads subsequent lines until another multi-line comment is encountered. All of these lines are ignored.

If the line is an instruction, skip is set to wslv. Whitespace at the beginning and end of line is removed. The U+002E FULL STOP at the beginning is removed. The line is then fed to the instruction parser. In case of an error, the parser MUST fail and load no further lines.

Otherwise, the line is text. Up to skip whitespace characters are removed since the beginning of line. If the first character after the removal is \, the character is removed.

If text references an object, create and push an object o with o.data equal to line and o.format equal to format, to text.

Instruction parser

cmd1  = fun1 *( 1*WSP arg1 )
fun1  = 4LOALPHA
arg1  = TAGS / SID / SIDN / ALEN / VAL / CID
arg1 /= UINT / TYPE / IREF / NAME

Instructions MUST match the <cmd1> rule.

The instruction parser converts the instruction line into a list of typed arguments and calls the function named by the instruction.

Instructions begin with a four-letter function name, followed by argument tokens, each preceeded by whitespace.

The parser MUST fail on any unrecognized function or argument, or when an argument is unexpected.

Argument tokens are defined such that a parser can determine the type of an argument from the input stream itself. The order of alternatives in <arg1> is the recommended order of tests.

Instruction parameters

This section defines syntax of instruction parameters.

Parameter rules use capital letters by convention.

Class identifier

CID   = "!" ( ID16 / %s"NOID" )
ID16  = 2HEXDIGIT 15( [ "-" ] 2HEXDIGIT )

The keyword NOID is the no-value ID (every octet is equal to zero).

Unsigned integer

UINT  = udec / uhex
udec  = 1*20DIGIT
uhex  = "0x" 1*16HEXDIGIT

Integer arguments are unsigned and may be at most 64-bit long. They are written in decimal or hexadecimal notation.

Symbol identifier

SID    = "#" UINT
SIDN   = "#" NAME "#" UINT

Because there are instructions with more than one symbol identifier, there are two variants: one with a name and one without.

Tags

TAGS = tag *( 1*WSP tag )
tag  = "+" 1*16LOALPHA

Tags are character string of up to 16 characters, which are preceeded by a U+002B PLUS SIGN character.

They are parsed into a list of strings.

Functions test for the presence of a tag in the list.

Name

NAME = LOALPHA *63( LOALPHA / DIGIT / "_" )

Items are given a human-readable name for reference. All letters in names MUST be small.

It is RECOMMENDED that names of functions be composed in subject-object-verb order, for example object_units_replace. This name requirement is for consistency and grouping of members.

Note that one can generate aliases in camelCase, too, if needed. Source code could be converted back and forth.

Item reference

IREF = [ mref ] 1*( "." NAME )
mref = NAME / CID

An item reference begins with a module reference, followed by a sequence of item names, each referring to an item declared as part of the preceeding item.

The module reference may be omitted as a shorthand for referencing the module declared by the currently parsed document.

References are resolved after all modules are loaded. Referenced item MAY be declared later in a document.

Object type

TYPE = hndt / cref

hndt = hndr "<" ( cref / %s"handle" / %s"?" ) ">"
hndr = %s"none" / %s"read" / %s"rdex" / %s"rdwr" / %s"rwex"

cref  = %s"octet" / %s"bool" [ %s"ean" ] / %s"status" / %s"cmprval"
cref /= %s"objsize" / %s"address" / %s"id16" / %s"uuid"
cref /= IREF ":" UINT

The type uuid is an alias for the id16 type.

Syntax of handles begin with access rights associated with the handle, followed by a type of referenced object in angle brackets. Handles may also reference objects of undefined (?) type or reference another handle in memory.

The type of object begins with an item reference to a class, followed by its level after a colon, or a predefined class name.

For example, read<stream.buffer:0> means a read-only handle to an instance of class buffer at level 0 from module stream.

Array length

ALEN = "[" [ mlen ":" ] arrl [ ":" arrl ] "]"
mlen = NAME *( "." NAME )
arrl = UINT / %s"MAX"

The special keyword MAX is an alias for 232-1.

Parsing examples:

         [10] => min =  10, max =  10, var = ()
       [1:20] => min =   1, max =  20, var = ()
      [1:MAX] => min =   1, max = MAX, var = ()
  [len:0:255] => min =   0, max = 255, var = ("len")
[obj.len:MAX] => min =   0, max = MAX, var = ("obj", "len")

Value

VAL  = "=" vval
vval = vreg / vref / vobj / varr / CID
vreg = valf / vali / valu / valb
vref = "&" IREF
vobj = "{" [ NAME "=" vval *( "," NAME "=" vval ) ] "}"
varr = "[" [ vval ] *( "," [ vval ] ) "]"

sign = "+" / "-"
vhex = "0x" 1*HEXDIGIT
vdec = 1*DIGIT
fdec = vdec [ "."    1*DIGIT ] [ "e" [ sign ] vdec ]
fbin = vhex [ "." 1*HEXDIGIT ] [ "p" [ sign ] vdec ]

valu = vhex / vdec
vali = sign valu
valf = [ sign ] ( "NaN" / "INF" / fdec / fbin )
valb = %s"true" / %s"false"

Values specify values of octets on given positions of an object. They can also be assigned to a name, creating a named value for reference.

The <VAL> rule is the most complex one; it contains recursion. Parsers MUST verify that all value lists are correctly terminated. Please study the rules calmly and thoroughly.

A register value can only be assigned to an instance of a register class; it is one of:

  • <valf>: real number.
  • <vali>: (signed) integer.
  • <valu>: unsigned integer.
  • <valb>: boolean; true is all bits set, false is all bits cleared.

<valn> references a named value.

<varr> is array of values. The target object MUST also be an array. The values in the array MUST be valid of the elements of the object. If the target array is longer, the excess values are undefined.

<CID> is a more readable notation for an array of 16 unsigned integers. Target objects of type id16 are expected, although, technically, any array of 16 or more integers is valid for this value.

<vobj> is a set of name-value pairs. The names reference a data member of the target object. It is an error if there is no data member with a matching name. Unreferenced members have undefined values.

Instruction processor

Functions are defined by listing their parameters in ascending order, describing the function and formally specifiying its outcome.

State of the instruction processor consists of the following variables:

  • mfin: level finalization state (boolean).
  • clvl: current class level (integer).
  • cbeg: current container (reference).
  • func: current function (reference).
  • data: current data member (reference).

An item name colllision between an item i and a name name occurs when any of the following is true: - For each data member d in i.data: d.name is equal to name. - For each function f in i.func: f.name is equal to name. - For each named value v in i.nval: v.name is equal to name. - For each named reference r in i.nref: r.name is equal to name.

A full name collision between a module m and a name name occurs if any of the following is true: - For each class c in m.types: c.name is equal to name. - item name collision occurs between m and name.

An SID collision occurs for a symbol identifier sid when any of the following is true: - For each data member d in mbeg.data: d.sid is equal to sid. - For each function f in mbeg.func: f.sid is equal to sid. - For each class c in mbeg.types: for each function f in c.func: f.sid is equal to sid.

A class level violation occurs in list when list is not an empty list and its last element i is such that i.clv is equal to or greater than cbeg.clv and i.mlv is less than mbeg.mlv.

The text function

Updates the format of item descriptions.

<NAME> type
Name of the new format.

The syntax of item descriptions is Markdown by default and may be changed at any point with the instruction.

Format names SHOULD be subtypes of text/ Internet Media Types.

An example:

This will be interpreted as _Markdown_ text.
.text html
<p>This will be interpreted as <b>HTML</b> text.</p>

Implementations MUST modify the state as follows:

  1. Set format to type.

The load function

References an external module.

<CID> mid
Module identifier.
<UINT> mlv
Required minimum level of the module.
<NAME> name (optional)
Alias for the module.

Modules reference items declared in other modules. A reference to a module that has not been loaded is invalid.

Item references are processed after all modules are loaded. Instruction lines do not have to appear before a reference. It is RECOMMENDED that they appear at the beginning of a document.

Implementations MUST return failure if any of the following is true:

  • mid is nil.
  • mlv is equal to or more than 216.
  • name was given and mbeg.mrefs has a tuple t with t.name equal to name.

Implementations MUST modify the state as follows:

  1. Find a tuple t in mbeg.mrefs with t.mid equal to mid.
  2. If found and t.mlv is less than mlv:
    1. Set t.mlv to mlv.
    Otherwise (if not found):
    1. Insert a new tuple (mid, mlv, name) into mbeg.mrefs.

The mbeg function

Begins declaration of a module (at level 0, finalized).

<CID> mid
Module identifier.

The instruction SHOULD NOT appear more than once in a KMDL document.

A module is a special kind of a class. Kueea Nodes have at most one instance of a given module. All module implementations share the same instance. In other words, modules are singleton objects.

Each node has its own instance of a module. The instances are only available at runtime. They are stored in volatile module memory.

The following functions are implicitly declared:

_create
Creates a new instance of the module.
Returns: No-access handle to the instance.
Called when there is no instance available.
_upgrade
Upgrades a module instance from a lower level.
Parameter: No-access handle to the old instance.
Returns: No-access handle to the new instance.
Called when the lowest level of all module implementations is higher than the level of the current instance. This also means that it is not possible for a node to load an implementation of a module at level lower than the level of the current module instance (as long as it exists).

Both of these functions can only be called by the kernel. Both of them require access to module memory, where the memory for an instance is allocated.

Implementations MUST return failure if any of the following is true:

  • mid is nil.
  • mbeg.mid is not mid.
  • mbeg.data is not empty.
  • mbeg.func is not empty.
  • mbeg.nval is not empty.
  • mbeg.nref is not empty.
  • mbeg.types is not empty.

Implementations MUST modify the state as follows:

  1. Set mbeg.mlv to 0.
  2. Set mfin to true.
  3. Set cbeg to nothing.
  4. Set func to nothing.
  5. Set data to nothing.
  6. Set text to mbeg.text.

The mlvl function

Increases the current level of the module.

<UINT> mlv
Module level.
<TAGS> tags
Tags associated with the level.

The new level applies to all items declared afterward. Module levels may only be increased.

tags contains either +final or +draft. If the level is final, no changes to it (and lower ones) will ever be made. This rule refers to the resulting tree of declared items;, descriptions of the items are not considered.

What this means is that if a KMDL document declares the same module as another, already known KMDL document, then the declared items in both of these documents MUST be the same, except for their textual descriptions.

Implementations MUST return failure if any of the following is true:

  • mbeg is nothing.
  • mlv is equal to 0, mbeg.mlv is equal to 0 and one of either: mbeg.data is not empty, mbeg.nval is not empty. mbeg.nref is not empty. mbeg.func is not empty. mbeg.types is not empty.
  • mlv is equal to or greater than 216.
  • mlv is less than mbeg.mlv.
  • tags contains both +final and +draft.
  • tags contains neither +final nor +draft.
  • tags contains +final and mfin is false.

Implementations MUST modify the state as follows:

  1. Set cbeg to nothing.
  2. Set func to nothing.
  3. Set data to nothing.
  4. Set text to mbeg.text.
  5. Set mfin to false if +draft in tags.
  6. Set mbeg.mlv to mlv.

The cbeg function

Begins a class declaration.

<NAME> name
Name of the class.
<TAGS> tags
Type of the class.
<CID> id (optional)
Identifier of the class.

If omitted, id becomes a version 5 UUID (namespace, SHA-1). The namespace UUID is the UUID of the module. The name is the name of the class (encoded in UTF-8).

If id is the nil UUID, the class will not have a descriptor. It will not have any creation functions. This is used to declare complex members for other classes.

The presence of +iface in tags changes the class declaration into a class interface declaration. Interfaces always have a CID (id cannot be nil).

Implementations MUST return failure if any of the following is true:

  • mbeg is nothing.
  • tags contains +iface and id is nil.
  • Item name collision occurs between cbeg and name.
  • There is a class c in mbeg.types, of which c.name is equal to name and c.cid is not equal to id.
  • id is not nil and there is a class c in mbeg.types, of which c.cid is equal to id and c.name is not equal to name.

Implementations MUST modify the state as follows:

  1. Find the class c in mbeg.types, of which c.name is equal to name.
  2. If c was not found:
    1. Set c to a newly created class.
    2. Insert c into mbeg.types.
    3. Set c.cid to id.
    4. Set c.clv to 0.
    5. Set c.name to name.
    6. Set c.tags to tags.
  3. Set cbeg to c.
  4. Set func to nothing.
  5. Set data to nothing.
  6. Set text to c.text.

The cend function

Explicitly ends a class declaration.

No parameters.

Implementations MUST modify the state as follows:

  1. Set cbeg to nothing,
  2. Set func to nothing,
  3. Set data to nothing.
  4. Set text to mbeg.text.

The clvl function

Modifies the current level of the current class.

<UINT> level
New level.

Implementations MUST return failure if any of the following is true:

  • cbeg is nothing.
  • level is equal to or more than 216.

Implementations MUST modify the state as follows:

  1. Set cbeg.clv to level.
  2. Set func to nothing.
  3. Set data to nothing.
  4. Set text to cbeg.text.

The creg function

Assigns a register type to a class.

<NAME> type
Register type.

This instruction declares that the class is a register class. Register classes are those for which exists a conversion between an object stored in memory and a register type stored in CPU registers.

reg1 = regf / regi / regu
regu = %s"u" ( "8" / "16" / "32" / "64" )
regi = %s"i" ( "8" / "16" / "32" / "64" )
regf = %s"f" (       "16" / "32" / "64" / "128" )

The first character of <reg1> is the class of a register. Remaining characters specify N - the width of the register.

Register classes are:

u
integer in the range [0, 2N-1]
i
integer in the range [-2N-1, 2N-1-1]
f
real number representable by the IEEE 754 binaryN format

Such classes implicitly declare the following read-write function members:

_save
Saves a value to memory.
Parameter: Register type; the value.
Returns: Nothing.
_load
Loads a value from memory.
Returns: Register type; the value.

Additionally, for integers:

_add
Loads, adds a value, saves.
Parameter: Register type; addend.
Returns: Boolean; value of the carry flag.
_sub
Loads, subtracts a value, saves.
Parameter: Register type; subtrahent.
Returns: Boolean; value of the carry flag.
_mul
Loads, multiplies by a value, saves.
Parameter: Register type; multiplier.
Returns: Register type; high bits of the result.
_div
Loads, divides by a value, saves.
Parameter: Register type; divisor.
Returns: Register type; remainder.
_neg
Only for signed integers.
Loads, negates the value, saves.
Returns: Register type; the saved value.
_and
Loads, does a bitwise AND, saves.
Parameter: Register type; bit mask.
Returns: Register type; the saved value.
_xor
Loads, does a bitwise XOR, saves.
Parameter: Register type; bit mask.
Returns: Register type; the saved value.
_inv
Loads, inverts all bits, saves.
Returns: Register type; the saved value.
_set
Loads, sets specified bits (bitwise OR), saves.
Parameter: Register type; bit mask.
Returns: Register type; the saved value.
_clr
Loads, clears specified bits, saves.
Parameter: Register type; bit mask.
Returns: Register type; the saved value.

Implementations MUST return failure if any of the following is true:

  • type does not match <reg1>.
  • cbeg is nothing.
  • cbeg.regt is non-empty.

Implementations MUST modify the state as follows:

  1. Set cbeg.regt to type.

The desc function

Declares the next data member, in memory order, of the descriptor.

<TYPE> type
Type of the object.
<NAME> name
Name of the object.
<ALEN> array (optional)
Length of an array.
<VAL> value
Value of the object. Default value if interface.
<UINT> align (optional)
Memory alignment.

Implementations MUST return failure if any of the following is true:

  • cbeg is nothing.
  • align was given and it is not an alignment.
  • For each data member d in cbeg.desc: d.name is equal to name.
  • Class level violation occurs in cbeg.desc.

Implementations MUST modify the state as follows:

  1. Create a new data member d.
  2. Set d.type to type.
  3. Set d.align to align.
  4. Set d.value to value.
  5. Set d.name to name.
  6. Set d.mlv to mbeg.mlv.
  7. Set d.clv to cbeg.clv.
  8. Append d to cbeg.desc.
  9. Set func to nothing.
  10. Set data to d.
  11. Set text to data.text.

These tests MUST be done once in the dereference phase:

  • type is not a register class.
  • value is out of range or has incorrect syntax.

The data function

Declares the next data member, in memory order.

<TYPE> type
Type of the object.
<NAME> name
Name of the object.
<ALEN> array (optional)
Length of an array.
<VAL> value (optional)
Default value.
<UINT> align (optional)
Memory alignment.
<TAGS> tags (optional)
Tags.
<SID> sid (optional)
Symbol identifier.

This function appends a data member either to the declaration of the class instance or to the declaration of the class desciptor.

Class descriptors are read-only objects, one per class, where each data member MUST have a declared value.

By default, align is the default alignment of type.

The following tags are recognized in tags:

+alt
Member is at the same address as the previous one.
+desc
Member is a member of the class descriptor.
+iobj
Member is an object of an implemented interface.
+prev
Merges the item description with the previous member's.

sid bears any meaning only when declaring a module-level member. Otherwise, sid MUST be omitted as there is no symbol. The default value is computed over name.

If tags contains +desc, let list be cbeg.data if cbeg is not nothing, otherwise let list be mbeg.data.

If tags does not contain +desc, let list be cbeg.desc if cbeg is not nothing, otherwise let list be mbeg.desc.

Implementations MUST return failure if any of the following is true:

  • alen is an invalid array length.
  • align is not an alignment.
  • tags contains both +iobj and +desc.
  • tags contains +alt and data is nothing.
  • tags contains +prev and data is nothing.
  • tags contains +desc and sid is not omitted.

Additionaly, if cbeg is nothing and tags contains +desc:

  • For each data member d in mbeg.desc: d.name is equal to name.

Additionaly, if cbeg is nothing and tags does not contain +desc:

  • full name collision occurs between mbeg and name.
  • SID collision occurs for sid.

Additionaly, if cbeg is not nothing and tags contains +desc:

  • class level violation occurs in cbeg.desc.
  • For each data member d in cbeg.desc: d.name is equal to name.

Additionaly, if cbeg is not nothing and tags does not contain +desc:

  • class level violation occurs in cbeg.data.
  • item name collision occurs between cbeg and name.

Implementations MUST modify the state as follows:

  1. Create a new data member d.
  2. Set d.type to type.
  3. Set d.tags to tags.
  4. Set d.array to array.
  5. Set d.align to align.
  6. Set d.value to value.
  7. Set d.mlv to mbeg.mlv.
  8. Set d.sid to sid.
  9. Set d.name to name.
  10. If cbeg is nothing:
    1. Set d.clv to cbeg.clv.
    2. If tags contains +desc:
      1. Append d to cbeg.desc.
      Otherwise (if tags does not contain +desc):
      1. Append d to cbeg.data.
    Otherwise (If cbeg is not nothing):
    1. If tags contains +desc:
      1. Append d to mbeg.desc.
      Otherwise (if tags does not contain +desc):
      1. Append d to mbeg.data.
  11. Set func to nothing.
  12. Set data to d.
  13. If tags does not contain +prev:
    1. Set text to d.text.

These tests MUST be done once in the dereference phase:

  • tags contains +iobj and type is not an interface.
  • alen.var is set and does not reference a member of an unsigned integer register class.
  • value was given and type is not a register class.
  • value was given and it is out of range or has incorrect syntax.
  • More than one of the alternatives have a defined value.

The nval function

Declares a named value.

<NAME> name
Name of the value.
<VAL> value
Named value.

Implementations MUST return failure if any of the following is true:

  • cbeg is nothing and full name collision occurs between mbeg and name.
  • cbeg is not nothing and item name collision occurs between cbeg and name.

Implementations MUST modify the state as follows:

  1. Create a new named value v.
  2. Set v.name to name.
  3. Set v.value to value.
  4. If cbeg is nothing:
    1. Append v to mbeg.nval.
    Otherwise (if cbeg is nothing):
    1. Append v to cbeg.nval.
  5. Set func to nothing.
  6. Set data to nothing.
  7. Set text to v.text

The nref function

Declares a name for an item reference (an alias).

<NAME> name
Name for an item.
<IREF> iref
Reference to the item.

The name is declared as part of the current module or class. The referenced item is not limited to the current module, however.

Implementations MUST return failure if any of the following is true:

  • cbeg is nothing and full name collision occurs between mbeg and name.
  • cbeg is not nothing and item name collision occurs between cbeg and name.

Implementations MUST modify the state as follows:

  1. Create a new named reference r.
  2. Set v.name to name.
  3. Set v.iref to iref.
  4. If cbeg is nothing:
    1. Insert r into mbeg.nref.
    Otherwise (if cbeg is not nothing):
    1. Insert r into cbeg.nref.
  5. Set func to nothing.
  6. Set data to nothing.
  7. Set text to r.text

The func function

Begins declaration of a normal function member.

<NAME> name
Name of the function.
<TAGS> tags (optional)
Tags.
<SID> sid (optional)
Symbol identifier.

The following tags are common to all function declarations:

+ro
Function does not write to the class instance.
+mod
Function requires access to module memory.
+krn
Function requires access to kernel memory.
+var
Function expects more parameters than declared.

If sid is omitted: if cbeg is not nothing, sid is computed over the concatenation of: cbeg.name, one U+0024 DOLLAR SIGN, name; otherwise, it is computed over just name.

Implementations MUST return failure if any of the following is true:

  • tags contains +init.
  • tags contains +fini.
  • tags contains +proto.
  • cbeg is nothing and SID collision occurs for sid.
  • cbeg is nothing and full name collision occurs between mbeg and name.
  • cbeg is not nothing and item name collision occurs between cbeg and name.

Implementations MUST modify the state as follows:

  1. Create a new function member f.
  2. Set f.tags to tags.
  3. Set f.mlv to mbeg.mlv.
  4. Set f.sid to sid.
  5. Set f.name to name.
  6. If cbeg is nothing:
    1. Insert f into mbeg.func.
    Otherwise (if cbeg is not nothing):
    1. Set f.clv to cbeg.clv.
    2. Insert f to cbeg.func.
  7. Set func to f.
  8. Set data to nothing.
  9. Set text to f.text.

The fret function

Declares the type of the return value of the current function.

<TYPE> type
Type of the value.

If the function does not return a value, then the document simply does not declare any return value.

Implementations MUST return failure if any of the following is true:

  • func is nothing.
  • func.rval references a type.
  • func.tags contains +init.
  • func.tags contains +fini.

Implementations MUST modify the state as follows:

  1. Set func.rval.type to type.
  2. Set text to func.rval.text.

The farg function

Declares the next in-order parameter to the current function.

<TYPE> itype
Input type of the parameter.
<NAME> name
Name of the parameter.
<TYPE> otype (optional)
Output type of the parameter.

The type of a function parameter is one of:

  • an object passed by value of length up to 128 octets,
  • an object passed by handle (by memory reference),
  • an object passed by reference to a handle (bidirectional handle),
  • a reference to an instance of a register class that is guaranteed to be accessed only by the function.

Objects passed by value are specified by simply writing a class reference.

.farg module.class:0 by_value

Objects passed by handle are written by specifying the handle.

.farg read<module.class:0> by_handle

Objects passed by a bidirectional handle (one that gives access to the function and back to the caller) are written as two handles.

.farg none<module.class:0> bidi_handle1 rdwr<module.class:0>
.farg rdwr<module.class:0> bidi_handle2 rdwr<module.class:1>

The bidi_handle1 parameter in the example is a reference to a handle. The function is not given any access rights to the refrenced memory. Upon return, the handle contains an address to an instance of module.class at level 0 and the caller receives read-write access to this object.

The bidi_handle2 parameter in the example is a reference to a handle. The function is given read-write access rights to an instance of module.class at level 0. Upon return, the handle contains an address to an instance of module.class at level 1 and the caller receives read-write access to this object.

The last category is written as two class references. The two references MUST reference a register class.

.farg int.u8 u8_ref int.u8

Their primary use is returning a small object in a situation when passing a buffer by handle would expose too much data to the function. This is also faster than passing by handle (no handle processing).

The referenced object may be safely copied before the call is made and then copied back to the original instance upon returning back.

Implementations MUST return failure if any of the following is true:

  • func is nothing.
  • func.tags contains +fini.
  • itype is a handle, otype was not omitted and is not a handle.
  • itype is a class reference, otype was not omitted and is not a class reference.

Implementations MUST modify the state as follows:

  1. Create a new function parameter p.
  2. Set p.name to name.
  3. Set p.itype to itype.
  4. Set p.otype to otype.
  5. Append p to func.params.
  6. Set text to p.text.

Additionaly, these tests MUST be done once in the dereference phase:

  • if itype and otype are class references and the referenced classes are of the same register type.

The init function

Begins declaration of a class constructor.

<NAME> name
Name of the constructor.
<TAGS> tags (optional)
Tags.
<SIDN> sid_init (optional)
Symbol identifier for the init symbol.
<SIDN> sid_create (optional)
Symbol identifier for the create symbol.

This function declares two function members: name_init and name_create.

The name_init function is a normal member function which takes the defined parameters as arguments and returns a status boolean.

The name_create function is a static member function which takes kernel-defined parameters first and then the defined parameters as arguments. The function returns a read-write handle to an instance of the class. It always requires access to the module context.

Compute name_init as follows:

  1. Let n be an empty string.
  2. Append _init to n.
  3. If name is equal to default, return n.
  4. Append one U+0024 DOLLAR SIGN to n.
  5. Append name to n.
  6. Return n.

Compute name_create as follows:

  1. Let n be an empty string.
  2. Append _create to n.
  3. If name is equal to default, return n.
  4. Append one U+0024 DOLLAR SIGN to n.
  5. Append name to n.
  6. Return n.

If omitted, sid_init is computed over the concatenation of: cbeg.name, one U+0024 DOLLAR SIGN, name_init.

If omitted, sid_create is computed over the concatenation of: cbeg.name, one U+0024 DOLLAR SIGN, name_create.

Implementations MUST return failure if any of the following is true:

  • tags contains +fini.
  • tags contains +proto.
  • cbeg is nothing.
  • cbeg.tags contains +alias.
  • For each function f in cbeg.func: f.sid is equal to sid_init or f.sid is equal to sid_create.

Implementations MUST modify the state as follows:

  1. Create a new function member create.
  2. Set create.tags to tags, create.mlv to mbeg.mlv, create.clv to cbeg.clv, create.sid to sid_create, create.name to name_create.
  3. Add +create to create.tags.
  4. Insert create into cbeg.func.
  5. Create a new function member init.
  6. Set init.tags to tags, init.mlv to mbeg.mlv, init.clv to cbeg.clv, init.sid to sid_init, init.name to name_init.
  7. Add +init to init.tags.
  8. Insert init into cbeg.func.
  9. Set func to init.
  10. Set item to init.
  11. Set text to item.text.

The fini function

Declares a class destructor.

<TAGS> tags (optional)
Tags.
<SID> sid (optional)
Symbol identifier.

Class destructors are predefined functions, which take one parameter: a read-write handle to a class instance. They return a status boolean.

By default, classes have no destructor. This function declares that one exists.

If omitted, sid is computed over the concatenation of: cbeg.name, one U+0024 DOLLAR SIGN, _fini.

Implementations MUST return failure if any of the following is true:

  • tags contains +init.
  • tags contains +proto.
  • cbeg is nothing.
  • cbeg.tags contains +alias.
  • For each function f in cbeg.func: f.sid is equal to sid.
  • For each function f in cbeg.func: f.tags does not contain +fini.

Implementations MUST modify the state as follows:

  1. Create a new function member fini.
  2. Set fini.tags to tags, fini.mlv to mbeg.mlv, fini.clv to cbeg.clv, fini.sid to sid, fini.name to _fini.
  3. Add +fini to fini.tags.
  4. Insert fini into cbeg.func.
  5. Set func to nothing.
  6. Set item to fini.
  7. Set text to fini.text.

The evnt function

Begins declaration of an event function.

<NAME> name
Name of the event.
<SIDN> sid_install (optional)
Symbol identifier for the install function.
<SIDN> sid_uninstall (optional)
Symbol identifier for the uninstall function.

Compute name_func as follows:

  1. Let n be an empty string.
  2. Append name to n.
  3. Append one U+0024 DOLLAR SIGN to n.
  4. Append func to n.
  5. Return n.

Compute name_install as follows:

  1. Let n be an empty string.
  2. Append name to n.
  3. Append one U+0024 DOLLAR SIGN to n.
  4. Append install to n.
  5. Return n.

Compute name_uninstall as follows:

  1. Let n be an empty string.
  2. Append name to n.
  3. Append one U+0024 DOLLAR SIGN to n.
  4. Append uninstall to n.
  5. Return n.

If omitted, sid_install is computed over: if cbeg is nothing, name_install; otherwise the concatenation of: cbeg.name, one U+0024 DOLLAR SIGN, name_install.

If omitted, sid_uninstall is computed over: if cbeg is nothing, name_uninstall; otherwise the concatenation of: cbeg.name, one U+0024 DOLLAR SIGN, name_uninstall.

The mesg function

Begins declaration of a message function.

<NAME> name
Name of the message.
<SID> sid (optional)
Symbol identifier.

Message functions always return a human-readable message.

The ifun function

Declares an implementation of a prototype function.

<IREF> proto
Reference to a prototype function.
<NAME> name
Name of the function (the implementation).
<TAGS> tags (optional)
Tags.
<SID> sid (optional)
Symbol identifier.

Implementations MUST return failure if any of the following is true:

  • tags contains +init.
  • tags contains +fini.
  • tags contains +proto.

The ival function

Declares a value of an interface descriptor's data member.

<IREF> member
Reference to an interface descriptor's data member.
<VAL> value
Value of the object.

Validation

After modules are successfully loaded, a processor MUST validate the modules before doing any further processing.

File Format URI

File Format URI of KMDL documents is rd://74RDM3TULLIOIPQ6V2GC3EZ3/2020/KMDL#Document.

Internet Media Type

Media type of KMDL documents is text/prs.kueea.kmdl.

The charset parameter MUST be included with the value UTF-8.



Menu