Self
Overview
Self is Bot Libre's JavaScript dialect that has been extend to support natural language processing. You can program your bot using the Self scripting language from your bot's Script page. You can also use Self from response templates, thinks, and conditions, and from the AIML "self" tag.
The Self scripting language is a state machine based language for scripting chat bots, it also enables bots to alter and program their own scripts.
Classes
Class | Description |
---|---|
Object | Self defines several object method available to all objects. |
String | String processing methods. |
Array | Array processing methods. |
Language | Natural language processing methods. |
Date | Date and time processing methods. |
Utils | Common utility methods. |
Math | Math operations.td> |
Http | HTTP, HTML, XML, JSON and web service processing methods. |
JSON | JSON processing methods. |
Facebook methods. | |
FacebookMessaging | Facebook messaging methods. |
Twitter messaging methods. | |
Telegram | Telegram messaging methods. |
Email methods. | |
Twilio | Twilio & SMS methods. |
Vision | Image and vision messaging methods. |
Context | Context access methods. |
Avatar | Avatar, emotion, poses, action, and command accessing methods. |
Mood | Mood and emotion methods. |
Operators
Operators | Description | Example |
---|---|---|
if | If statement. | if (value == null) { ... } else { ... } |
for | For statement. | for (word in sentence.word) { ... } |
while | While statement. | while (count < 10) { ... } |
do | Do statement. | do { ... } |
think | The same as do but can be used inside a Template to perform some code but not print a value into the response. | think { ... } |
return | Return the value. | if (word == "hello") { return "hello there"; } |
== | Compare if two values match. | apple == apple |
!= | Compare if two values don't match. | apple != orange |
< | Compare if a value is less than another. | if (time < 10) { greeting = "Good Morning!"; } |
<= | Compare if a value is less or equal than another. | if (time <= 12) { greeting = "Have a Nice Day!"; } |
> | Compare if a value is greater than another. | if (time > 12) { greeting = "Good Afternoon!"; } |
>= | Compare if a value is greater or equal than another. | if (time >= 5) { greeting = "Nice Day!"; } |
! | negates a logical value | negative = !negative; |
&& | Logical AND. | if (x < 5 && y > 2) { ... } |
|| | Logical OR. | if (x < 5 || y > 1) { ... } |
= | Variable assignment. | name = "Alice"; |
++ | Increment a variable. | var step; for (step = 0; step < 5; step++) { ... } |
-- | Decrement a variable. | var step; for (step = 10; step < 5; step--) { ... } |
+ | Add two numbers or concatenate two strings. | txt1 = "John"; txt2 = "Smith"; txt3 = txt1 + " " + txt2; |
- | Subtract two numbers. | var x = 5; var y = 2; var z = x - y; |
* | Multiply two numbers. | var x = 5; var y = 2; var z = x * y; |
/ | Divide two numbers. | var x = 10; var y = 2; var z = x / y; |
new | Construct a new object. | response = new Sentence(); |
Symbol | Create a new global symbol. | Language.define(word, Symbol(word)); |
. | Get a relationship from an object. | age = speaker.age; |
= | Set a relationship on an object. | response.word[0] = "Hello"; |
=+ | Add a relationship on an object. | sentence.response =+ response; |
=- | Remove a relationship on from object. | sentence.response =- response; |
random | Select and execute random value. | random("Hello", "Hi", "Hey", "G'day mate"); |
redirect | Evaluate the response to the phrase. | redirect("what is " + star); |
srai | Synonym for redirect (AIML syntax). | srai("hello"); |
request | Evaluate the response to the phrase using a remote service. | request(song, { service : #wikidata, hint : "performer")); |
sraix | Synonym for request (AIML syntax). | sraix(song, { service : #wikidata, hint : "performer")); |
learn | Learn a new response. | learn( {pattern:"hello", template:"how are you" } ); |
eval | Evaluate code within a learned pattern or template. | learn( {pattern:Pattern("what is {eval (star[0])}"), template:Template("{eval (star[1])}") } ); |
debug | Print the arguments to the log. | debug(star); debug (#error, error) |
Object
Object Methods | Description | Example |
---|---|---|
add(key, value) | Add a relationship value to the object. | speaker.add(#name, "Bob") |
all(key) | Returns an array of all of the object's relationship values for the type. | speaker.all(#name) |
addWithMeta(key, vale, metaType, meta) | Add a relationship value to the object with the relationship meta data. | |
append(key, value) | Append the value to the end of the object's relationship. | response.append(#word, ".") |
appendWithMeta(key, vale, metaType, meta) | add a relationship value to the object with the relationship meta data | |
copy() | Return a shallow copy of the object. | object.copy() |
dataType() | Return the primitive data-type of the object or null. | object.dataType() == #String |
delete() | Delete the object, (use this with caution). | object.delete() |
delete(key, value) | Delete the relationship. | object.delete(#type, value) |
deleteAll() | Delete all relationships. | object.deleteAll(), |
deleteAll(key) | Delete all the relationships of the type. | object.deleteAll(#type), |
findReference() | Inverse references lookup. Returns first reference. | |
findReferenceBy(key) | Inverse relationship lookup. Returns first reference. | |
findReferences() | Inverse references lookup. Returns array of objects. | |
findReferencesBy(key) | Inverse relationship lookup. Returns array of objects. | |
get(key) get(key, index) | Get a relationship value from an object, optional index. | speaker.get(#name), sentence.get(#word, 3) |
getAccessCount() | Return the object's access count. | object.getAccessCount() > 100 |
getAccessDate() | Return the object's access date. | object.getAccessDate() |
getAccessDate(key, value) | Return the relationship's access date. | object.getAccessDate(#type, value) |
getConsciousnessLevel() | Return the object's consciousness level. | object.getAccessDate() |
getConsciousnessLevel(key, value) | Return the relationship's consciousness level. | object.getAccessDate(#type, value) |
getCorrectness(key, value) | Return the relationship's correctness. | object.getCorrectness(#type, value) |
getCreationDate() | Return the object's creation date. | object.getCreationDate() |
getCreationDate(key, value) | Return the relationship's creation date. | object.getCreationDate(#type, value) |
getGroupId() | Return the object's group id. | object.getGroupId() |
getId() | Return the object's unique id. | object.getId() |
getId(key, value) | Return the relationship's unique id. | object.getId(#type, value) |
getIndex(key value) | Return the relationship's index. | list.getIndex(#element, value) |
getKey(value) | Return the related objects relationship key. | object.getKey(value) |
getLast(key) getLast(key, start) | Get a relationship value from the end of an ordered relationship. | conversation.getLast(#input, 1) |
getName() | Return the object's primitive name. | object.getName() |
getWithAssociate(key, associate, associateType) | Get a relationship value from an object most associate to the other value. | |
has(key, value) | Return if the relationship exists. | speaker.has(#name, "Bob") |
hasAny(key) | Return if the object has any relationship of the type. | object.hasAny(#type) |
hasData() | Return if the object has primitive data (String, Number, Date, etc.). | object.hasData() |
hasMeta(key, value) | Return if the relationship has a meta value. | object.hasMeta(#type, value) |
isArray() | Return if the object is an array. | object.isArray() |
isPinned() | Return if the object is pinned. | object.isPinned() |
isPinned(key, value) | Return if the relationship is pinned. | object.hasMeta(#type, value) |
isSymbol() | Return if the object is a primitive symbol. | object.isPrimitive() |
keys() | Return an array of the object relationship keys. | for (key in object.keys()) { .. } |
meta(key, value) | Return the relationship's meta value. | object.meta(#type, value) |
pin() | Pin the object. | object.pin() |
pin(key, value) | Pin the relationship. | object.pin(#type, value) |
random(key) | Return a random element of the relationship type. | object.random(#type) |
remove(key, value) | Remove the relationship value (this creates an inverse relationship). | speaker.remove(#name, "Bob") |
removeWithMeta(key, value, metaType, meta) | Remove the relationship value with the relationship meta data. | |
set(key, value) set(key, value, index) | Sets a relationship value on an object. | speaker.set(#age, 44) |
setCorrectness(key, value, value) | Sets a relationship value on an object. | speaker.setCorrectness(#gender, #male, 0.5) |
size(key) | Returns the number of relationships of the type. | object.size(#type) |
toJSON() | Convert the object to a JSON string. | object.toJSON() |
toXML() | Convert the object to an XML string. | object.toXML() |
toString() | Convert the object to string. | object.toString() |
unpin() | Unpin the object. | object.unpin() |
unpin(key, value) | Unpin the relationship. | object.unpin(#type, value) |
weakAdd(key, value) | Add a relationship value to the object with a low correctness. | |
weakAddWithMeta(key, value, metaType, meta) | Add a relationship value to the object with a low correctness with the relationship meta data. |
String
String Methods | Description | Example |
---|---|---|
charAt(index) | Return the string's character at the index. | "hello".charAt(0) == "h" |
concat(text) | Concatenate the two strings. | "hello".concat(" world!") == "hello world!" |
endsWith(text) | Return if the string ends with the text. | "hello world".endsWith("world") == true |
exec(text) | Convert the string to a regex pattern and evaluates if it matches the text and return the text match. | "/\d+".exec("123") == "123" |
indexOf(text) | Return the index of the substring or -1 if missing. | "hello world".indexOf("hello") == 0 |
lastIndexOf(text) | Return the last index of the substring or -1 if missing. | "hello world hello".indexOf("hello") == 12 |
length() | Return the string's length. | "hello".length() == 5 |
match(text) | Convert the string to a regex pattern and return an array of all matching values. | "/\d+".match("123 plus 456") == ["123" "456"] |
replace(token, text) | Replace all occurances of the token string with the text. | "hello world".replace("hello", "goodbye") == "goodbye world" |
setCharAt(index, char) | Return a string with the string's character at the index. | "hello".setCharAt(0, "H") == "Hello" |
size() | Return the string's length. | "hello".size() == 5 |
startsWith(text) | Return if the string starts with the text. | "hello world".startsWith("hello") == true |
substr(start, end) | Return the string substring. | "hello world".substr(0, 4) == "hell" |
substring(start, end) | Return the string substring. | "hello world".substring(0, 4) == "hell" |
test(text) | Convert the string to a regex pattern and return if it matches the text. | "/\d+".test("123") == true |
toLowerCase() | Return the string as lower case. | "HELLO".toLowerCase() == "hello" |
toUpperCase() | Return the string as upper case. | "hello".toUpperCase() == "HELLO" |
toNumber | Convert the string to a number. | "123.4".toNumber() |
toSymbol | Convert the string to a primitive symbol. | "topic".toSymbol() |
trim() | Trim leading and trailing whitespace. | "     Hello World!     ".trim() == "Hello World!" |
Array
Array Methods | Description | Example |
---|---|---|
add(value) | Add the value to the end of the array's elements. | array.add("hello") |
delete(value) | Delete the value from the array's elements. | array.delete("hello") |
has(value) | Return if the array contains the element. | array.has("hello") |
indexOf(value) | Return the index of the element in the array. | array.indexOf("hello") |
indexOf(value, start) | Return the index of the element in the array starting at the index. | array.indexOf("hello", 4) |
lastIndexOf(value, start) | Return the index of the element in the array starting at the end. | array.lastIndexOf("hello") |
length() | Return the arrays length. | [1, 2, 3].length() == 3 |
random() | Return a random element of the array. | array.random() |
size() | Return the arrays length. | [1, 2, 3].length() == 3 |
Language
Language Methods | Description | Example |
---|---|---|
word(text*) | Creates a compound word. | Language.word("ball", "hockey") |
sentence(text*) | Creates a sentence. | Language.sentence("How", "are", "you") |
define(text, object) | Defines the word as meaning the value. | Language.define("foobar", #foobar) |
Date
Date Methods | Description | Example |
---|---|---|
date() | Current Date object. | var today = Date.date(); |
date(text) | Convert the text or Timestamp to a Date. | var xmas = Date.date("2017-12-25"); |
time() | Current Time object. | var time = Date.time(); |
time(text) | Convert the text or Timestamp to a Time. | var noon = Date.time("12:00:00"); |
timestamp() | Current Timestamp object. | var now = Date.timestamp(); |
timestamp(text) | Convert the text or Date to a Timestamp. | var timestamp = Date.timestamp("2017-10-02 16:52:30"); |
any(text) | Parse any date/time format. | var name = Date.parse("Sept 3, 2014") |
add(date, part, time) | Add the date value (#day, #month, #year, #hour, #minute, #second, #millisecond). | var tomorrow = Date.add(Date.date(), #day, 1); |
get(date, part) | Return the date part (#day, #month, #year, #hour, #minute, #second, #millisecond). | var day = Date.get(Date.date(), #day); |
set(date, part, value) | Set the date part (#day, #month, #year, #hour, #minute, #second, #millisecond). | var day = Date.set(Date.date(), #day, 11); |
difference(from, to, part) | Compute the date/time difference from date part (#day, #month, #year, #hour, #minute, #second, #millisecond). | var days = Date.difference(Date.date(), Date.date("2017-12-25"), #day); |
interval(part, from, to) | Compute the date/time interval from date/time formatted strings ("days", "months", "years", "hours", "minutes", "seconds", "milliseconds"). | var days = Date.interval("days", "2017-11-20", "2017-12-25") |
interval(part, from, to, format) | Compute the date/time interval from date/time Java SimpleDateFormat formatted strings ("days", "months", "years", "hours", "minutes", "seconds", "milliseconds"). | var days = Date.interval("days", "2017-11-20", "2017-12-25", "yyyy-MM-dd") |
getTimeZone() | Return the default time zone. | var gmt = Date.getTimeZone(); |
getTimeZone(zone) | Return the timezone object based on its timezone code i.e. "GMT", "GMT-5", "PST", "America/Los_Angeles". | var gmt = Date.getTimeZone("GMT"); |
setTimeZone(date, timezone) | Set the dates time zone based on its timezone code i.e. "GMT", "GMT-5", "PST", "America/Los_Angeles". | var est = Date.setTimeZone(Date.date(), "EST"); |
printAIMLDate(date, format) | Print the date using the AIML format. | |
printDate(date, format) | Print the date using Java SimpleDateFormat format. | var dateString = Date.printDate(Date.date(), "yyyy-MM-dd") |
Utils
Util Methods | Description | Example |
---|---|---|
encode(text) | Converts to URL encoded character. | Http.requestXML("http://api.com/fetch?name=" + Utils.encode(name)) |
denormalize(text) | Converts punctuation words back to characters. | Utils.denormalize("That is cool colon ) at dash at") == "That is cool :) @-@" |
normalize(text) | Converts punctuation characters to the word values. | Utils.normalize("That is cool :) @-@") == "That is cool colon ) at dash at" |
explode(text) | Expands a string to its character values. | Utils.explode("hello") == "h e l l o" |
extract(text, pattern) | Convert the pattern to a regex pattern and extracts the matching string from the text. | Utils.extract("the cost is $123", "\d+") == "123" |
extractValue(text, pattern) | Convert the pattern to a regex pattern and extracts the matching string from the text. | Utils.extractValue("tell me what is life", "what.is.(.*)") == "life" |
matches(text, pattern) | Convert the pattern to a regex pattern and returns if the text matches. | Utils.matches("123", "/\d+") == true |
gender(text) | Converts between 'he' and 'she'. | Utils.gender("he likes her") == "she likes him" |
person(text) | Converts between 1st and 2nd person. | Utils.person("I love myself") == "you love yourself" |
person2(text) | Converts between 1st and 3rd person. | Utils.person2("I love myself") == "he love himself" |
capitalize(text) | Converts the first character to upper case. | Utils.capitalize("hello there") == "Hello there" |
sentence(text) | Converts the first character to upper case. | Utils.sentence("hello there") == "Hello there" |
formal(text) | Converts the first character to upper case for each word. | Utils.formal("hello there") == "Hello There" |
lowercase(text) | Converts to lower case. | Utils.lowercase("HELLO There") == "hello there" |
uppercase(text) | Converts to upper case. | Utils.uppercase("hello there") == "HELLO THERE" |
program() | Returns the current software name and version. | |
size() | Returns to total knowledge base size (total objects). | |
version() | Returns the current software version. | |
id() | Returns the bot's internal id. |
Math
Math Methods | Description | Example |
---|---|---|
add(x, y) | Sum of x and y values. | Math.add(2, 3); 5 |
subtract(x, y) | Subtract y from x value. | Math.subtract(8, 5); 3 |
multiply(x, y) | Multiply x and y values. | Math.multiply(2, 4); 8 |
divide(x, y) | Divide x and y values. | Math.divide(18, 9); 2 |
abs(x) | Returns the absolute value of x. | Math.abs(-7.7); 7.7 |
floor(x) | Returns the value of x rounded down to its nearest integer. | Math.floor(3.8); 3 |
ceil(x) | Returns the value of x rounded up to its nearest integer. | Math.ceil(2.2); 3 |
power(x, y) | Returns the value of x to the power of y. | Math.power(7, 2); 49 |
round(x) | Returns the value of x rounded to its nearest integer. | Math.round(4.3); 4 |
log(x) | Math.log(8); 3 | |
ln(x) | ||
sin(x) | Returns the sine of x (x is in radians). | Math.cos(0); 1 |
asin(x) | ||
cos(x) | Returns the cosine of x (x is in radians). | |
acos(x) | ||
tan(x) | Returns the tangent of an angle. | |
tanh(x) |
Http
Http | Description | Example |
---|---|---|
toJSON(object) | Convert an object to JSON text. | |
toXML(object) | Convert an object to XML text. | |
encode(text) | URL encode the text. | |
requestJSON(url) | Fetch the JSON response. | |
requestJSON(attribute, url) | Fetch the JSON response. | |
requestJSON(attribute, url, headers) | Fetch the JSON response. Pass custom headers as JSON object. | |
requestJSONAuth(attribute, url, user, password) | Call authenticated API and fetch the JSON response. | |
requestXML(url) | Fetch the XML response. | |
requestXML(url, xpath) | Fetch the XML response. | |
requestXML(url, xpath, headers) | Fetch the XML response. Pass custom headers as JSON object. | |
requestXMLAuth(url, user, password, xpath) | Call authenticated API and fetch the XML response. | |
requestHTML(url, xpath) | Scrape the HTML page. | |
requestHTML(url, xpath, format) | Scrape the HTML page, return #text, #array, #html, or #object. | |
requestHTML(url, xpath, format, subformat) | Scrape the HTML page, return #array of #text, #html, or #object. | |
requestCSV(url) | Parse the CSV file. | |
requestText(url) | Return the raw text data. | |
requestText(url, headers) | Return the raw text data. Pass custom headers as JSON object. | |
rss(url) | Fetch the last RSS feed. | |
rssFeed(url) | Fetch the entire RSS feed. | |
postJSON(url, object) | Post the JSON object to the URL. | |
postJSONAuth(url, user, password, object) | Post the JSON object to the URL. | |
postXML(url, object) | POST the XML object to the URL. | |
postXML(url, object, xpath) | POST the XML object to the URL. Extract the XPath data. | |
postXMLAuth(url, user, password, object, xpath) | Post the XML object to the URL. Extract the XPath data. | |
postHTML(url, params, xpath) | Post the HTML form parameters to the URL. Extract the XPath data. | |
putJSON(object) | PUT the JSON object to the URL. | |
delete(url) | Send an HTTP DELETE to the URL. |
JSON
JSON | Description | Example |
---|---|---|
parse(text) | Parse an object from JSON text. | |
stringify(object) | Convert an object to JSON text. |
Description | Example | |
---|---|---|
post(message) | Post to the bot's Facebook page. | |
postComment(comment, postid) | Post to the bot's Facebook page. | |
sendMessage(message, userid) | Send a message to a user. |
FacebookMessaging | Description | Example |
---|---|---|
sendMessage(message, userid) | Send a message to a user. | |
sendMessage(message, userid, command) | Send a message to a user with a custom Facebook quick_reply or attachment command. |
Description | Example | |
---|---|---|
tweet(message) | Tweet to the bot's Twitter account. | |
sendMessage(message, userid) | Send a direct message to a user. |
Telegram
Telegram | Description | Example |
---|---|---|
post(message) | Post to the bot's Telegram channel. | |
sendMessage(message, userid) | Send a message to a user. | |
sendMessage(message, userid, command) | Send a message to a user with a Telegram custom keyboard reply_markup command. | |
postJSON(url, json) | Call a Telegram bot API with the JSON parameter. |
Description | Example | |
---|---|---|
email(address, subject, message) | Send an email from the bot's email account. | Email.email("[email protected]", "Welcome", "Thanks for registering.") |
Twilio
Twilio | Description | Example |
---|---|---|
sms(number, message) | Send a SMS messages from the bot's Twilio account. | Twilio.sms("613-123-4567", "Escalation alert") |
Vision
Vision | Description | Example |
---|---|---|
loadImage(url) | Load the image into the bot's memory. | |
matchImage(url, tag, error) | Search for the closest matching image for the tag. |
Context
Context | Description | Example |
---|---|---|
push(object) | Push the object to the current context stack. | |
top() | Return the top of the context stack. | |
top(index) | Return the nth top of the context stack. | |
search(match) | Search the context stack for a matching object. |
Avatar
Avatar | Description | Example |
---|---|---|
setAction(action) | Set the avatar's action. | |
setPose(pose) | Set the avatar's pose. | |
setCommand(command) | Set a JSON command object. |
Mood
Mood | Description | Example |
---|---|---|
setEmotion(emotion, value) | Set the value of the emotion (between -1.0 and +1.0). | Mood.setEmotion(#Happiness, 1.0) |
State Operations
State Operation | Description | Example |
---|---|---|
state | A state defines the current input processing. | pattern "my name is *" template Template("Pleased to meet you {star}"); |
case | A case can transition to another state if the case variable matches the current input. | case "lol" template "Very funny." |
pattern | A pattern can match an input and evaluate a template response. | pattern "hello" template "Hi there"; |
answer | An answer of a state is evaluated if the input processing is complete. | answer Template("Pleased to meet you {star}"); |
function | An function can be called from an answer or another function. | function todayResponse() { var response = new (#sentence); response.append(#word, "Hello World!"); return response; } |
var | A variable can be matched with the current input, or store context. | var name { instantiation : #name; } |
Pattern Operators
Operator | Description |
---|---|
* | Matches one or more words. |
_ | Matches one or more words, takes priority over all other words and wildcards, except $. |
^ | Matches zero or more words. |
# | Matches zero or more words, takes priority over all other words and wildcards, except $. |
$ | Pattern priority marker to make a pattern word match highest priority. |
() | Optional set of words. |
[] | Required set of words. |
<set> | Set tag to evaluate a pattern based on words defined in a predefined set. |
/ | Regular expression pattern. |
{} | Self code. |
Examples
Here example of a Self script that counts words:
// Example script that counts words.
state CountWords {
pattern "count words in *" answer countWords();
function countWords() {
var words = Language.sentence(star);
var count = 0;
for (word in words.word) {
count = count + 1;
}
return Template("There are {count} words.");
}
}
Here example of a Self script that repeat words:
// Example script that repeat words.
state Repeat {
pattern "repeat * by * times" answer repeat();
function repeat() {
var response = "";
var repeat = star[1].toNumber();
var count = 0;
while (count < repeat) {
response = response + " " + star[0];
count = count + 1;
}
return response;
}
}
Here example of a Self script that access an XML web API:
// This script searches Wikipedia using an XML HTTP request and an XPath expression to scrape the description text.
state SearchWikipedia {
pattern "what is *" answer search();
function search() {
return Http.requestXML("https://en.wikipedia.org/w/api.php?action=opensearch&format=xml&limit=1&search=" + Utils.encode(star), "/SearchSuggestion/Section/Item/Description/text()");
}
}
Here example of a Self script that uses patterns to perform math:
// Script for understanding simple math using patterns.
state SimpleAddition {
pattern "* + *" answer (Math.add(star[0].toNumber(), star[1].toNumber()));
pattern "* - *" answer (Math.subtract(star[0].toNumber(), star[1].toNumber()));
pattern "* / *" answer (Math.divide(star[0].toNumber(), star[1].toNumber()));
pattern "* x *" answer (Math.multiply(star[0].toNumber(), star[1].toNumber()));
}
The state machines are more complex, but allow you to parse arbitrarily complex expressions. Here example of a Self script use a state machine and variables for processing addition:
// Language state machine for understanding simple {x+y} addition.
state SimpleAddition {
// This line is required for any state processing to process each word in the input phrase.
case input goto sentenceState for each #word of sentence;
state sentenceState {
case left goto numberState;
// The left variable is a stand-in for any word that represents a number, the 'number' variable will be assign the value of the number.
// The meaning is required because in Self words are just words that represent an object which is the meaning of the word, multiple words can have the same meaning.
var left {
meaning : number;
}
var number {
instantiation : #number;
}
// '123...'
state numberState {
// You could also use,
// case "+" goto numberPlusState;
// But #plus is a bootstrap symbol for all + characters and words
case plus goto numberPlusState;
var plus {
meaning : #plus;
}
// '123 +...'
state numberPlusState {
case right goto numberPlusNumberState;
// A second number2 variable is required for the right side of the addition operation to capture the value.
var right {
meaning : number2;
}
var number2 {
instantiation : #number;
}
// '123 + 123'?
state numberPlusNumberState {
case "?" goto numberPlusNumberState;
answer (Math.add(number, number2));
}
}
}
}
}