Add map and array support
kirsle opened this issue · 0 comments
Add support for hash maps and arrays in RiveScript.
Maps
Maps would be global variables (like bot variables). Their purpose is to hold simple key/value style data to simplify the reply structure for holding knowledge (examples would be: capitals of the states, etc.)
Syntax example:
// Define a map name and add key/value pairs one at a time
! map capitals CA = Sacramento
! map capitals MI = Lansing
// Define a map, provide the mappings immediately
! map capitals =
^ CA = Sacramento
^ MI = Lansing
// This would also have worked, but isn't as readable and won't be
// the preferred syntax:
! map capitals = CA = Sacramento
^ MI = Lansing
// If you "re-define" a map using the above syntax (provide the mappings
// immediately) on a map that already exists, your new key/value pairs
// will be merged with the existing ones. So you can add key/value pairs
// in bulk multiple times throughout your code with no problems. Map keys
// are always unique, though, so if you use the same key twice the value
// will be overwritten.
// Example of maps in use:
+ what is the capital of _
* <exists capitals <uppercase>> == true => The capital of <uppercase> is:\s
^ <map capitals <uppercase>>.
- I don't know what the capital of <uppercase> is.
New tags added to support maps:
<exists MAP_NAME KEY_NAME>
- returns "true" ifKEY_NAME
exists inMAP_NAME
<map MAP_NAME>
- returns the full contents of the map, in JSON format (mostly useful for debugging)<map MAP_NAME KEY_NAME>
- get the value of that key, orundefined
if it doesn't exist<map MAP_NAME KEY_NAME=VALUE>
- dynamically reassign the value of a key in the map (the key doesn't need to exist in advance).
User Maps?
Some syntax ideas to support maps as user variables.
+ i have a (@colors) *
- <set %colors:<star1>=<star2>>Okay.
+ do you know about my *
* <get %colors:<star>> != undefined => Yes, your\s
^ <star> was colored <get %colors:<star>> right?
- You didn't tell me what color it is.
Human> I have a blue car
Bot> Okay.
Human> Do you know about my car?
Bot> Yes, your car was colored blue right?
The existing <get>
and <set>
tags would be repurposed for map variables. A map variable always has its name prefixed with a %
symbol (like in Perl). To refer to a specific key, use a colon symbol ":".
<get %name>
- would dump the map as JSON, for debugging<get %name:key>
- get the named key from the map, or "undefined"<set %name:key=value>
- set a key<set %name:key=undefined>
- delete a key by setting it to undefined (consistent with all other variable-setting tags). Maybe add a<delete>
tag instead that works on all variable types (user vars, anyway)?
Sets
Sets would be arrays for user variables, for holding a list of things in one variable.
Syntax examples:
+ i like the color *
- <add @color=<star>>I'll remember that you like <star>.
+ what colors do i like
- You like: <get @color>.
// would output e.g.: "You like: red, green, blue."
Existing variable-setting tags would be re-used, but array names are prefixed with an @ symbol.
Sets would work like the data type of the same name in Python: its contents would be de-duplicated. If you add the same item to the set twice, it only ends up going in one time.
Tags:
<get @name>
- returns a comma separated list of values<get @name:length>
- get the number of elements in the set<get @name[0]>
- get an item from the list by index<add @name=value>
- add a value to the set<delete @name=value>
- remove a value from the set
Iteration?
Some ideas to support iterating over set elements without making the syntax too ugly?
+ what are my favorite colors
* <get @colors:length> >= 2 => They are:\s
^ {iter @colors[:-1]}<item>,{/iter} and <get @colors[-1]>.
* <get @colors:length> == 1 => There is only <get @colors[0]>.
- You didn't tell me any.
Human> What are my favorite colors?
(if they have 2 or more)
Bot> They are: red, blue, yellow, and green.
(if they have 1)
Bot> There is only red.
(if none)
Bot> You didn't tell me any.
Tags:
{iter LIST}...{/iter}
- Creates an iterator over the list-like object,
LIST
. The code between the opening and closing tag will be run for each item inLIST
, and the new<item>
tag would hold the current item.
- Creates an iterator over the list-like object,
<item>
- holds the current item in an iterator; only available inside an{iter}...{/iter}
block.
Array index slices would work like in Python, so colors[:-1]
meant "all colors except for the last one", example:
>>> colors = ["red", "blue", "yellow", "green"]
>>> colors[:-1]
['red', 'blue', 'yellow']