Skip to content

Literals

One of the main features of Ryna is that it allows the programmer to define many new elements of the syntax. One of these are literals, which can be defined for any valid class. Let's see how this works.

Basic classes

The firt part of this is the syntax of basic types. Not all of them have types, but the ones that do are the basic building blocks for more compplicated literals. Here is a table with the basic types that do have a syntax:

Type NDL Pattern Regex
Int ["-"] 1{d} -?\d+
Float ["-"] 1{d} "." 1{d} -?\d+\.\d+
Bool "true" | "false" true|false
String No constaint .*

Everything that follows these syntaxes can be parsed as an instance of this type.

Creating a literal

In order to create a new literal you first have to create a new class that the literal will be parsed to. Also, this class's attributes must also have at least a syntax. Here is an example class thaht represents a number of D&D dice rolls:

class Dice {
    rolls: Int;
    sides: Int;
}

let d = Dice(5, 20); // Throw a 20 sided dice 5 times 

Now, the readers that have played D&D know that this value is often represented as 5D20. We can define this simple syntax using Ryna:

class Dice {
    syntax from Arg(1{d}, rolls) "D" Arg(1{d}, sides);

    rolls: Int;
    sides: Int;
}

let d = 5D20; // Throw a 20 sided dice 5 times 

Here the Arg NDL marker tells the interpreter that the syntax of a Dice consist on an integer (the rolls) followed by a D and, finally, another integer (the sides). After this, the class Dice can also be parsed inside an NDL pattern. Now let's take a look at a different use case: an integer array:

class Ints {
    syntax from "[" Arg(1{d}, ints) {", " Arg(1{d}, ints)} "]";

    ints: Array<Int>;
}

let a: Ints = [1, 2, 3];

This case shows how the interpreter works when an Arg marker with the same target is matched several times. Each time it matches, the result is parsed inside an Array of the type it parses.