Time of page creation
Time of the last page update

DRAFT: Kueea Module Declaration Language

This document is a working draft.

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 and module documentation in HTML or other formats. They are part of tool chains that build Kueea Module implementations.

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.

Module

Processing a KMDL document produces a tree of declared items. Most items have an associated human-readable textual description, which is only used when generating module documentation.

Items are associated with a module level to which they belong. Higher levels include all items declared by lower levels.

The root of the tree is the module item. Its children are:

  • classes,
  • class interfaces,
  • class aliases,
  • enumerations,
  • functions,
  • function prototypes,
  • function prototype implementations,
  • read-only data objects,
  • read-write data objects,
  • static messages,
  • dynamic messages,
  • events.

Classes and interfaces are containers. Their children are functions (methods) and class levels. Interfaces may additionaly contain function prototypes and classes may contain interface function implementations.

Class levels are lists of data members.

Data members are lists of data members. If there is more than one element in the list, the member is a union. Named unions are declared as classes.

Enumerations are aliases for a PCS class (defined later) with an associated set of named values within the range of the class.

Functions are lists of parameters.

Static messages are special kind of read-only data members. Dynamic messages are special kind of functions.

Events are special objects and function prototypes (for a handler).

Syntax

A KMDL document is a sequence of Unicode characters. A parser processes the document line by line. Maximum length of a line is 1024 octets, including the line separator.

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.

There are three kinds of lines:

  • processor instructions,
  • item descriptions, and
  • comments.

Comments

Comments are lines that are ignored by the parser.

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.

Comment sections 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 comment section.
This is a comment.
.This is a comment.
# # This is inside a comment section.
  ## This is the last line of a comment section.
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.

Parameters to the instruction follows the name, separated by whitespace.

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

.inst param1 param2
   .inst param1

Item descriptions

Any other line is text - a human-readable textual description of the item declared by the most-recent item-declaration instruction.

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

Their specific syntax is out of scope of this document.

.item ex1
Description of the ex1 item.

Description of the ex1 item.

.item ex2

Description of the ex2 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

The following KMDL rule expresses the syntax in ABNF. The encoding of string literals is UTF-8.

KMDL  = "." mbeg CRLF *( line CRLF ) ; mbeg defined later
line  = comm / inst / text

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

inst  = *WSP "." name *( 1*WSP parm ) *WSP
name  = 4LOALPHA
parm  = 1*VCHAR

text  = [ *WSP "\" ] *OCTET

Syntax and parameters of instructions are defined (also using ABNF) in their respective sections later in the document. These rules match the name *( 1*WSP parm ) fragment of inst.

Instruction lines MUST NOT contain code points above U+007F. These code points MAY be used in comments and item descriptions.

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

Parser

State of a KMDL parser consists of the following variables:

  • line: current line,
  • wslv: current line indentation,
  • skip: ignored line indentation.

The parser takes a sequence of Unicode characters as input. Some of the parsed lines are then fed to a KMDL processor.

When reading lines, the line is buffered without the line separator.

The parser begins by setting skip to zero. It then reads the first line into line.

If line does not begin with .mbeg, the parser MUST fail. Otherwise, all trailing whitespace characters in line are removed. The line is then fed to a processor as an instruction. In case of an error, the parser MUST fail and read no further.

The parser then reads all remaining lines in the input sequence. Each new line is buffered in line and processed as follows.

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 comment section line, the parser reads subsequent lines until another comment section line is encountered. All of these lines are ignored.

If the line is an instruction line, skip becomes wslv. Whitespace at the beginning and end of line is removed. The line is then fed to a processor as an instruction. In case of an error, the parser MUST fail and read no further.

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. The line is then fed to the processor as text.

Processor

State of a KMDL processor consists of the following variables:

  • load: set of module representations,
  • mode: current section,
  • mbeg: current module,
  • mlvl: current module level,
  • mfin: boolean indicating module finalization state,
  • cbeg: current class or interface,
  • clvl: current class level,
  • func: current function,
  • item: current item,
  • text: current text format.

The processor takes as input a module identifier. The output is a representation of the identified module.

Representation of a module consists of:

  • the loaded state (loaded, being loaded or unloaded),
  • its identifier (UUID),
  • extm: a list of pairs of name and module identifier,
  • a representation of the module tree (the items).

When an item is created, it MUST be associated with the current value of mlvl. How items are represented is a property of a particular implementation.

The processing begins (or ends) by clearing the load set. A new unloaded module is created and inserted into load. Its module identifier is the one given as input to the processor.

The processor then enters a loop in which it loads all unloaded modules in load until there are no more unloaded modules.

Loading of a module begins by setting mbeg to the module. If the module has already been loaded, nothing needs to be done.

Otherwise, the processor opens a file corresponding to the module by means outside the scope of this document and invokes the parser on said file. The parser then feeds back parsed lines to the processor. If the parser fails, the processor MUST fail, too. The module is then marked as loaded.

After all modules are loaded, the processor resolves all item references. The processor MUST fail if an undeclared name is referenced.

The processor returns the representation of the requested module tree.

Item description

Each item is described by a list of data-format pairs.

Whenever the processor reveives a text line from the parser, a new pair is appended to the description of item, with the data being the received line and format being text.

The data is then fed line by line to the appropriate processor. The input to that processor ends whenever the format changes or there is no more pairs in the item-description list.

Output from the processors is appended to a single buffer.

Common instruction parameters

This section defines rules for parameters commonly used by instructions.

Integers

Integers are unsigned and may be 16, 32, or 64-bit long. They are written in decimal or hexadecimal notation.

u16    = u16dec / u16hex
u16dec = 1*5DIGIT
u16hex = "0x" 1*4HEXDIGIT

u32    = u32dec / u32hex
u32dec = 1*10DIGIT
u32hex = "0x" 1*8HEXDIGIT

u64    = u64dec / u64hex
u64dec = 1*20DIGIT
u64hex = "0x" 1*16HEXDIGIT

Universally Unique Identifier

Modules, classes and interfaces 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 syntax is the URN textual notation of a UUID. [RFC4122]

uuid = 8HEXDIGIT 3( "-" 4HEXDIGIT ) 8HEXDIGIT
; example: 12345678-1234-AbCd-1234-aBcD12345678

The value 00000000-0000-0000-0000-000000000000 is reserved as the no-value (nil) value.

Item name

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

There MUST NOT be two items with the same name within a container. Containers are module items, classes, interfaces, enumerations.

name = ( LOALPHA / "_" ) *( LOALPHA / DIGIT / "_" )

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. Note that one can generate aliases in camelCase, too, if needed.

Symbol identifier

Global objects and functions are found via their symbol. Symbols are identified by a 64-bit unsigned integer.

There MUST NOT be two symbols within a module with the same value.

sid  = u64

By default, the value is the result of hashing a UTF-8 character string using the FNV-1a (Fowler-Noll-Vo) hash function with a 64-bit prime. Symbol values should only be explicitly declared if case of a collision.

For items that are children of a module, the hashed string is the name of an item. For example: global.

For members of a class or interface, the hashed string is the concatenation of: name of the class or interface, a U+0024 DOLLAR SIGN character and the name of a member. For example: class$member.

Class reference (object type)

type = tpre / cref
tpre = %s"octet" / %s"boolean" / %s"compared"
cref = [ mref ] "." name ":" u16
mref = name / uuid

There are three predefined types of objects:

  • octet: eight bits; the fundamental type; bits have no meaning,
  • boolean: one bit; occupies one octet as a data member; its value range is false (0) or true (1),
  • compared: two bits; occupies one octet as a data member; result of a comparision; its value range is 11 for error, 10 for less-than, 00 for equal and 01 for greater-than.

All other types are classes defined by a module.

A class reference begins with the module identifier or its alias, followed by the name of a class and its level.

In case of interfaces, the level is always 0.

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

References are resolved after the parsing phase finishes. Referenced item MAY be declared later in a document.

Function return value

fval = type / hndt / %s"void"

hndt = hndp "<" ( type / %s"undef" ) ">"
hndp = %s"none" / %s"read" / %s"rdex" / %s"rdwr" / %s"rwex"

Return value of functions may be one of:

  • no value (void),
  • predefined type (octet, boolean, compared),
  • instance of a class passed by value (up to 128 octets),
  • instance of a class passed by memory reference (handle).

The syntax for the last one (handle) needs explanation.

Memory references in Kueea System have associated access rights. Access rights associated with a handle are one of:

none
No access rights.
read
Read-only access.
rdex
Read and execute rights.
rdwr
Read and write rights.
rwex
Read, write and execute rights.

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 (undef) type.

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

Reserved item names

The reserved global names are:

  • construct,
  • destruct,
  • state_verify.

The reserved member names are:

  • save,
  • load,
  • preconstruct,
  • access_update,
  • all names beginning with create.

The mbeg instruction

mbeg = %s"mbeg" 1*WSP uuid

KMDL documents begin with the mbeg instruction. This instruction must not have any preceeding whitespace. It declares the identifier of the module defined by the document.

This instruction MUST NOT appear more than once in a KMDL document.

The processor MUST fail if any of the following is true:

  • mbeg is in any other state that unloaded.

This instruction MUST modify the state as follows:

  • mark mbeg as being loaded,
  • set mode to MODULE,
  • set mlvl to 0,
  • set mfin to false,
  • set cbeg to nothing,
  • set func to nothing,
  • set item to mbeg,
  • set text to markdown.

The mlvl instruction

Items defined by a module are grouped into levels. By default, the value of the module level is zero. The level can be changed with the mlvl instruction.

mlvl = %s"mlvl" 1*WSP u32 [ 1*WSP %s"fin" ]

The first parameter is the new value of the module level. The level applies to all items declared after the instruction.

The optional second parameter is the finalization flag. It indicates that the level in question has been finalized.

The processor MUST fail if any of the following is true:

  • the new value is lower than mlvl,
  • the finalized flag was not given and mfin is true.

This instruction MUST modify the state as follows:

  • set cbeg to nothing,
  • set func to nothing,
  • set item to mbeg,
  • set mlvl to the new value,
  • set mfin to true if the finalization flag was given.

The load instruction

Modules reference items defined in other modules. These modules must be loaded or else references will not resolve.

load = %s"load" 1*WSP uuid 1*WSP u32 [ 1*WSP name ]

The first parameter to the load instruction is the identifier of the module to be loaded.

The second parameter is the required level of the module.

The optional third parameter is a name given to that module.

The load instruction can appear at any point in the module. It does not have to appear before a reference to it. It is RECOMMENDED that these instructions appear at the beginning of a document, though.

The processor MUST fail if any of the following is true:

  • mbeg has a pair in its extm with the name equal to <name>, but only if one was specified.

This instruction MUST modify the state as follows:

  • insert a new pair matching the arguments into extm,
  • create and insert a new unparsed module with the given identifier into load, but only if there was no such module.

The text instruction

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

text = %s"text" 1*WSP tfmt *( 1*WSP tpar )
tfmt = 1*VCHAR
tpar = 1*VCHAR

The first parameter is the name of the new format. The name SHOULD be a subtype of a text media type.

All subsequent parameters are parameters of the format.

An example:

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

This instruction MUST modify the state as follows:

  • update text accordingly.

The calt instruction

calt = %s"calt" 1*WSP type 1*WSP name

This instruction declares a named reference to a class.

The first parameter is a reference to a class.

The second parameter is the name, the alias.

The processor MUST fail if any of the following is true:

  • mode is not MODULE,
  • there is a child item named <name> in mbeg.

This instruction MUST modify the state as follows:

  • create and insert a new class reference item to mbeg,
  • set item to the reference.

The cbeg instruction

cbeg = %s"cbeg" 1*WSP name [ 1*WSP ( uuid / %s"none" ) ]

This instruction begins a section that declares a class.

The first parameter is a name of the class.

The second parameter is an identifier of the class. By default, it is a version 5 (namespace with SHA-1) UUID. The namespace UUID is the UUID of the module. The name is the name of the class, encoded in UTF-8.

If the second parameter is none, the class will not be exported. This is used to declare complex members that are part of a union.

The processor MUST fail if any of the following is true:

  • there is a child item named <name> in mbeg and this item is not a class,
  • there is an interface in mbeg with the same UUID.

This instruction MUST modify the state as follows:

  • set mode to CLASS,
  • set cbeg to a class named <name> in mbeg; if the class does not exist, create a new class,
  • set clvl to 0 if a new class was created; otherwise to the greatest value of all class levels in cbeg plus one,
  • set func to nothing,
  • set item to the class.

The ibeg instruction

ibeg = %s"ibeg" 1*WSP name [ 1*WSP uuid ]

This instruction begins a section that declares an interface.

Parameters and their meaning are the same as for the cbeg instruction.

The processor MUST fail if any of the following is true:

  • there is a child item named <name> in mbeg,
  • there is a class or interface in mbeg with the same UUID.

This instruction MUST modify the state as follows:

  • set mode to INTERFACE,
  • set cbeg to a newly created interface,
  • set clvl to 0,
  • set func to nothing,
  • set item to the interface.

The cend instruction

cend = %s"cend"

This instruction explicitly ends a class or interface section.

This instruction MUST modify the state as follows:

  • set mode to MODULE,
  • set cbeg to nothing,
  • set func to nothing,
  • set item to mbeg.

The clvl instruction

clvl = %s"clvl" 1*WSP u16 [ 1*WSP u16 ]

This instruction MUST NOT appear in an interface section.

Class members are grouped into levels, similarly to a module. The default value of a class level is zero.

The first parameter is the value of a class level.

The second parameter is the memory address alignment of an instance at this level.

The processor MUST fail if any of the following is true:

  • mode is not CLASS,
  • the memory alignment is not a power of 2,
  • the class level value is lower than or equal to values of all existing class levels currently declared in cbeg.

This instruction MUST modify the state as follows:

  • insert a new class level of the given value to cbeg,
  • set func to nothing,
  • set clvl to the new level.

The cpcs instruction

cpcs = %s"cpcs" 1*WSP pcst
pcst = pcsu / pcss / pcsf
pcsu = %s"u" (  "8" / "16" / "32" /  "64" )
pcss = %s"s" (  "8" / "16" / "32" /  "64" )
pcsf = %s"f" ( "16" / "32" / "64" / "128" )

This instruction MUST NOT appear in an interface section.

This instruction declares that the class is a PCS class. PCS classes are those for which exists a conversion between an object stored in memory and a value stored in a CPU register(s).

Such classes implicitly define two function members: save and load. The first one saves a value to memory, the second one loads it. In C, these functions are invoked like this:

class object;
pcs   value;

class$save(&object, value);
value = class$load(&object);

This instruction takes a PCS type as its sole argument. PCS types are those that a CPU may have a dedicated register for.

The first character is the type of a value. Remaining characters specify the value of N.

The value types are:

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

The processor MUST fail if any of the following is true:

  • mode is not CLASS,
  • cbeg has already been marked as a PCS class.

This instruction MUST modify the state as follows:

  • mark cbeg as a PCS class of type <pcst>.

The data instruction

data = %s"data" 1*WSP type 1*WSP memb [ 1*WSP u16 ] [ 1*WSP "=" vpcs ]
memb = name [ "[" [ mlen ":" u32 ":" ] u32 "]" ]
mlen = name *( "." name )

vpcs = valu / vals / valf
valu = 1*DIGIT / "0x" 1*HEXDIGIT
vals = [ sign ] valu
valf = [ sign ] valu [ "." valu ] [ "e" [ sign ] valu ]
sign = "+" / "-"

This instruction declares the next data member of a class or an interface.

Data members are laid out in memory in the order they are declared.

The first parameter is the type of the object. In the case of handles, the access rights are bound to an instance. If there are two handles to the same object, only one of them needs to have rights to the object.

The second parameter is the name for the data member. If there is a [ following the <name>, the member is an array. The length is given as an integer between [ and ].

When the array length has the form [mlen:u32:u32], the member is a variable-length array.

The name MUST reference a previously defined member, which MUST be an instance of a PCS unsigned integer class. This member holds the actual length of the array. The value after the first colon defines the minimum array length. The value after the second colon defines the maximum array length.

This is not for specifying how much memory is to be allocated. The value is used in calculation of the minimum and maximum lengths of a class instance, which is stored in its class descriptor. Offsets of all subsequent members are calculated at runtime.

The third parameter (optional) is an override of the default memory address alignment requirement of the member. Padding is inserted before the member if it is not properly aligned. Authors must consider alignment and padding when designing classes.

The fourth parameter (optional, preceeded by =) is the default value of the member, type of which MUST be a PCS class. The syntax of the value MUST correspond to the PCS type.

The processor MUST fail if any of the following is true:

  • mode is not CLASS or INTERFACE,
  • <name> is a reserved member name,
  • if an array and cbeg does not have the referenced member,
  • cbeg already has a member with the same name.

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

  • if an array and the referenced member's type is not an unsigned integer PCS class,
  • if there is a value and the type of the member is not a PCS class,
  • if there is a value and it is out of range or has incorrect syntax.

This instruction MUST modify the state as follows:

  • append a new member to class level clvl in cbeg,
  • set func to nothing,
  • set item to the instered data member.

The dalt instruction

dalt = %s"dalt" 1*WSP type 1*WSP memb [ 1*WSP u16 ]

This instruction declares a new member of the current union. It implicitly redeclares the previously defined data member as a union.

Parameters are the same as for data with the exception that no default value can be specified as it is already declared by the first member.

The alignment of the union is the highest value of all its members.

The processor MUST fail if any of the following is true:

  • item is not a data member,
  • <name> is a reserved member name,
  • if an array and cbeg does not have the referenced member,
  • cbeg already has a member with the same name.

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

  • if an array and the referenced member's type is not an unsigned integer PCS class.

This instruction MUST modify the state as follows:

  • append a new data member to item,
  • set item to the appended data member.

The func instruction

func = %s"func" 1*WSP fval 1*WSP name [ 1*WSP sid ] *( 1*WSP fbit )
fbit = %s"mod" / %s"krn"

This instruction declares a normal function.

The first parameter is the return value of the function.

The second parameter is the name of the function.

The third parameter (optional) is the symbol identifier of the function.

The fourth and further parameters (optional) are function flags. Only two flags are defined:

mod
Function requires access to its module context.
krn
Function requires access to the kernel context.

The function is either a global function or a method of a class, depending on the current processor state.

The processor MUST fail if any of the following is true:

  • mode is not CLASS, INTERFACE or MODULE,
  • mode is MODULE and <name> is a reserved global name,
  • mode is MODULE and mbeg already has a child item with the same name,
  • mode is CLASS or INTERFACE and <name> is a reserved member name,
  • mode is CLASS or INTERFACE and cbeg already has a member with the same name.

This instruction MUST modify the state as follows:

  • if mode is MODULE, insert a new function to mbeg; otherwise, insert a new function to cbeg,
  • set func to the function,
  • set item to the function.

The farg instruction

farg = %s"farg" 1*WSP ( argt 1*WSP name / "..." )
argt = type / hndt / tref
tref = "[" ( type / hndt ) "]"
thnd = hndt ":" hndp [ "<" ( type / %s"undef" ) ">" ]

This instruction declares the next in-order function parameter. The variable-argument-list parameter (farg ...) MUST be the last one.

The first parameter to the instruction is the type of the argument or three consecutive periods that indicate a variable argument list.

The second parameter is the name of the argument for reference.

Types of function parameters are 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 PCS class that is guaranteed to be modified 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 access rights and then the type of the object surrounded in angle brackets.

.farg read<module.class:0> by_handle1 ; read-only  access
.farg rdwr<module.class:0> by_handle2 ; read-write access

Objects passed by a bidirectional handle (one that gives access to the function and back to the caller) are written in square brackets. Inside the brackets are the handle passed to the function, then a colon and the handle passed back to the caller. If the type is the same, it can be omitted.

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

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, 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, level 1 and the caller receives read-write access to this object.

The last category is written as a class reference in angle brackets. This is a reference to an instance of a PCS class.

.farg [int.u8] u8_ref

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 buffer upon returning back.

The processor MUST fail if any of the following is true:

  • func is nothing,
  • item is a variable-argument-list parameter.

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

  • if <type> is a PCS type reference and the referenced type is not a PCS class.

This instruction MUST modify the state as follows:

  • append a new function parameter to func,
  • set item to the appended parameter.

The mfpd instruction

fpro = %s"mfpd" 1*WSP fval 1*WSP name

This instruction declares a function prototype. MFPD stands for "module function prototype declaration."

The first parameter is the return value of the function.

The second parameter is the name of the item.

The processor MUST fail if any of the following is true:

  • mode is not MODULE,
  • <name> is a reserved global name,
  • mbeg already has a child item with the same name.

This instruction MUST modify the state as follows:

  • insert a new function prototype to mbeg,
  • set func to the function prototype,
  • set item to the function prototype.

The mfpi instruction

mfpi = %s"mfpi" 1*WSP mfpr 1*WSP name [ 1*WSP sid ] *( 1*WSP fbit )
mfpr = [ mref ] "." name

This instruction declares an implementation of a function prototype. MFPI stands for "module function prototype implementation."

The first parameter is a reference to the function prototype. The item MUST be declared with an mfpd instruction.

The second parameter is the name of the function implementation.

The third parameter (optional) is the symbol identifier of the function.

The fourth and further parameters (optional) are function flags. The flags are exactly the same as for normal functions.

Because theis is an implementation of an already-described prototype, the function has the same description as the referenced prototype.

Arguments are the same as for the prototype.

The processor MUST fail if any of the following is true:

  • mode is not MODULE,
  • <name> is a reserved global name,
  • mbeg has a child item with the same name.

This instruction MUST modify the state as follows:

  • insert a new function implementation to mbeg,
  • set func to nothing,
  • set item to mbeg.

The cfpd instruction

cfpd = %s"cfpd" 1*WSP fval 1*WSP name [ %s"ro" ] *2( 1*WSP sid )

This instruction declares a function prototype and two functions for calling the implemented prototype as part of an interface. CFPD stands for "class interface function prototype declaration."

The first parameter is the return value of the function.

The second parameter is the name of the item.

The third parameter (optional) is the read-only flag.

The fourth parameter (optional) is the symbol identifier of the first function, named <name>.

The fifth parameter (optional) is the symbol identifier of the second function, named by concatenating <name> with $call.

The first parameter to the first function depends on the read-only flag. If given, it is a read-only handle to an undefined object; otherwise, it is a read-write handle to an undefined object.

The first function obtains the interface descriptor of the object and then calls the second function, which calls the function implementation.

The second function has an additional argument as the first: a read-only handle to the interface descriptor.

For example, the following KMDL:

.ibeg iface
.ifpd void function
.farg .u32 arg1

would become the following (C syntax, names for clarity):

void iface$function(void* this, u32 arg1);
void iface$function$call(iface const* iface, void* this, u32 arg1);

The second function exists for a case when multiple functions are called in succession to avoid the overhead of quering for the descriptor. It is implicitly declared and MUST NOT be part of the module tree.

The processor MUST fail if any of the following is true:

  • mode is not INTERFACE,
  • <name> is a reserved member name,
  • cbeg already has a member with the same name.

This instruction MUST modify the state as follows:

  • insert a new function prototype to cbeg,
  • set func to the prototype,
  • set item to the prototype.

The cimp instruction

cimp = %s"cimp" 1*WSP ( uuid / mfpr ) 1*WSP u16

This instruction declares that a class implements an interface.

The first parameter is the UUID of the interface or a named reference to an interface.

The second parameter is the class level at which the interface is implemented.

The processor MUST fail if any of the following is true:

  • mode is not CLASS,
  • clvl is higher than the given level.

This instruction MUST modify the state as follows:

  • mark class level clvl in cbeg as implementing the referenced interface.

The cfpi instruction

cfpi = %s"cfpi" 1*WSP cfrf 1*WSP name [ 1*WSP sid ] *( 1*WSP fbit )
cfpr = uuid "." name / [ mref ] "." name "." name

This instruction declares an implementation of an interface function prototype. CFPI stands for "class interface function prototype implementation."

The first parameter is a reference to the function prototype. The item MUST be declared with an cfpd instruction.

The second parameter is the name of the function implementation.

The third parameter (optional) is the symbol identifier of the function.

The fourth and further parameters (optional) are function flags. The flags are exactly the same as for normal functions.

Because this is an implementation of an already-described prototype, the function has the same description as the referenced prototype.

Arguments are the same as for the prototype's first function, except that the handle is to the class instead of an undefined object. The level depends on the level declared with the cimp instruction.

The processor MUST fail if any of the following is true:

  • mode is not CLASS,
  • <name> is a reserved member name,
  • cbeg already has a member with the same name.

This instruction MUST modify the state as follows:

  • insert a new function implementation to cbeg,
  • set func to nothing,
  • set item to cbeg.

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.