aichaos/rivescript-wd

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" if KEY_NAME exists in MAP_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, or undefined 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 in LIST, and the new <item> tag would hold the current item.
  • <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']