Custom types

Defining a new generic color type based on RGB values

Custom types can be defined using built-in types and other custom types. In this way, an entire hierarchy of types can be built up. To demonstrate how custom types are defined, I will implement a type my-color, because color is perfectly suited to visualize the concept of types, although a type color already exists. In contrast to the existing color type, I want my-color to match rgb(...), i.e. the string rgb followed by a 3-tuple with the values for red, green and blue.

Defining a custom type is similar to defining a sentence as shown earlier, indeed defineSentence is just a shortcut for defining (or extending) the type sentence:

JavaPythonJavaScript
Parser parser = new Parser();
parser.defineType("my-color", "rgb({red:int}, {green:int}, {blue:int})", pn -> {
    int red = (int) pn.evaluate("red");
    int green = (int) pn.evaluate("green");
    int blue = (int) pn.evaluate("blue");
    return new int[] {red, green, blue};
});
parser = Parser()

def evaluateColor(pn):
    red = pn.evaluate("red")
    green = pn.evaluate("green")
    blue = pn.evaluate("blue")
    return (red, green, blue)

parser.defineType(
    "my-color",
    "rgb({red:int}, {green:int}, {blue:int})",
    evaluateColor)
let parser = new nlScript.Parser();
parser.defineType(
    "my-color",
    "rgb({red:int}, {green:int}, {blue:int})",
    pn => {
        let red = pn.evaluate("red")
        let green = pn.evaluate("green")
        let blue = pn.evaluate("blue")
        return [red, green, blue];
    });

defineType has 3 arguments:

The new type can now be used in defineSentence, or to define other types via defineType:

parser.defineSentence("Set the drawing color to {color:my-color}.", ...);

Defining a new generic color type based on a set of named colors

We can also define a new type with a fixed set of options, i.e. a set of pre-defined named colors. This is implemented by repeatedly defining a type with different patterns:

JavaPythonJavaScript
Parser parser = new Parser();
parser.defineType("my-color", "white", pn -> new int[] { 255, 255, 255 });
parser.defineType("my-color", "black", pn -> new int[] {   0,   0, 0   });
parser.defineType("my-color", "red",   pn -> new int[] { 255,   0, 0   });
parser.defineType("my-color", "green", pn -> new int[] {   0, 255, 0   });
...
parser.defineSentence("Set the drawing color to {color:my-color}.", ...);
parser = Parser()
parser.defineType("my-color", "white", lambda pn: (255, 255, 255))
parser.defineType("my-color", "black", lambda pn: (  0,   0,   0))
parser.defineType("my-color", "red",   lambda pn: (255,   0,   0))
parser.defineType("my-color", "green", lambda pn: (  0, 255,   0))
...
parser.defineSentence("Set the drawing color to {color:my-color}.", ...);
let parser = new nlScript.Parser();
parser.defineType("my-color", "white", pn => [255, 255, 255]);
parser.defineType("my-color", "black", pn => [  0,   0,   0]);
parser.defineType("my-color", "red",   pn => [255,   0,   0]);
parser.defineType("my-color", "green", pn => [  0, 255,   0]);
...
parser.defineSentence("Set the drawing color to {color:my-color}.", ...);

Combining generic and preset type definitions

The above two concepts can also be combined, which allows the user to select a color from a pre-defined list, but also leaves the freedom to provide a custom color which is not in the list, by specifying its RGB values:

JavaPythonJavaScript
Parser parser = new Parser();
parser.defineType("my-color", "rgb({red:int}, {green:int}, {blue:int})", pn -> {
    int red = (int) pn.evaluate("red");
    int green = (int) pn.evaluate("green");
    int blue = (int) pn.evaluate("blue");
    return new int[] {red, green, blue};
});
parser.defineType("my-color", "white", pn -> new int[] { 255, 255, 255 });
parser.defineType("my-color", "black", pn -> new int[] {   0,   0, 0   });
parser.defineType("my-color", "red",   pn -> new int[] { 255,   0, 0   });
parser.defineType("my-color", "green", pn -> new int[] {   0, 255, 0   });
...
parser.defineSentence("Set the drawing color to {color:my-color}.", ...);
parser = Parser()

def evaluateColor(pn):
    red = pn.evaluate("red")
    green = pn.evaluate("green")
    blue = pn.evaluate("blue")
    return (red, green, blue)

parser.defineType(
    "my-color",
    "rgb({red:int}, {green:int}, {blue:int})",
    evaluateColor)

parser.defineType("my-color", "white", lambda pn: (255, 255, 255))
parser.defineType("my-color", "black", lambda pn: (  0,   0,   0))
parser.defineType("my-color", "red",   lambda pn: (255,   0,   0))
parser.defineType("my-color", "green", lambda pn: (  0, 255,   0))
...
parser.defineSentence("Set the drawing color to {color:my-color}.", ...);
let parser = new nlScript.Parser();
parser.defineType(
    "my-color",
    "rgb({red:int}, {green:int}, {blue:int})",
    pn => {
        let red = pn.evaluate("red")
        let green = pn.evaluate("green")
        let blue = pn.evaluate("blue")
        return [red, green, blue];
    });
parser.defineType("my-color", "white", pn => [255, 255, 255]);
parser.defineType("my-color", "black", pn => [  0,   0,   0]);
parser.defineType("my-color", "red",   pn => [255,   0,   0]);
parser.defineType("my-color", "green", pn => [  0, 255,   0]);
...
parser.defineSentence("Set the drawing color to {color:my-color}.", ...);