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
:
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:
A name for the type, which can be used in later type definitions
Like an integral number is of type int
, our color will be of type my-color
.
A pattern that defines how the type should be parsed"rgb({red:int}, {green:int}, {blue:int})"
means that our new type will consist of the string 'rgb', followed by a 3-tuple with integral values named 'red', 'green' and 'blue' for the red, green and blue color component. my-color
consists of three variables red
, green
and blue
, which are of type int
and which can be accessed in the evaluator by their name.
An evaluator
The evaluator returns an object corresponding to the parsed and interpreted type, here an int[]
(Java), a tuple
(Python) or an array
(JavasScript), with the red, green and blue color components as elements.
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}.", ...);
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:
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}.", ...);
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:
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}.", ...);