# UPIL Language
The UPIL language was designed to allow both developers and non-developers to describe "scenarios", or high-level flows of interaction between a user and an application. UPIL has several high-level entities to allow you to interact with a user. UPIL also includes other concepts for describing high-level business-logic including conditional logic, loading data from external sources, and external actions.
# Entity Structure
Most entities have the following structure:
<Entity Name> <Optional Label>
<Entity Contents>
/<Entity Name>
2
3
For example:
TEMPLATE myLabel
"Message to user"
/TEMPLATE
2
3
EXTERNAL
, RUN
, and ACTION
entities have a simpler structure:
EXTERNAL currentTemp
ACTION sendEmail
RUN main
TEMPLATE
entites also have a simple version:
Text only:
TEMPLATE "Hi there"
Label only:
TEMPLATE overrideThis
# User-Interaction
User interaction is performed using three main entities: TEMPLATE
, SELECT
, and MULTI_SELECT
. All three entities can save user input to a variable with the >>myVariable
syntax. This allows the user input to be referenced and used later on in the scenario.
# Template
A TEMPLATE
entity is for displaying text to a user. TEMPLATE
s can also request a user's input.
TEMPLATE
for greeting the user with the text "Hi there!":
TEMPLATE "Hi there!"
Example TEMPLATE
with user input request saved to the variable name
:
TEMPLATE
"What is your name?"
>>name
/TEMPLATE
2
3
4
# Selects
# SELECT
A SELECT
is used to request the user to select a single choice from a list of choices. It requires the user input to be saved to a variable.
SELECT
"Please choose your favorite color"
-("Red", "red")
-("Blue", "blue")
-("Green", "green")
>>color
/SELECT
2
3
4
5
6
7
# MULTI_SELECT
A MULTI_SELECT
is similar to a SELECT
, only it allows users to select more than one choice from a list
MULTI_SELECT
"Please choose all of your favorite colors"
-("Color red", "red")
-("Color blue", "blue")
-("Color green", "green")
>>colors
/MULTI_SELECT
2
3
4
5
6
7
# Options
There are several ways to write options in a SELECT
or MULTI_SELECT
# Default case
-("Color red", "red")
The default case presents the user with an option Color red
, while saving red
in the select's variable.
# Simplified case
- "Red"
The simplified version would use Red
both for the option text, and the value saved in the select's variable.
# Value types
The value of an option can be a literal
such as a string, number, or boolean:
String:
-("Color red", "red")
Number:
-("Five cars", 5)
Boolean:
-("Call taxi", true)
The value of an option can also come from a variable. This is specified by using a variable name without quotes. If the variable doesn't exist, then the UPIL engine will assume it should use the variable name as a string value.
Variable:
-("My car", usersCar)
Here is an example of using the above variable case:
## Resolves to ferrari
EXTERNAL usersCar
DIALOG main
SELECT
"Which car do you want?"
-("My car", usersCar)
-("Default", "honda accord") >>carSelection
/SELECT
TEMPLATE "Have fun driving a ${carSelection}"
/DIALOG
RUN main
2
3
4
5
6
7
8
9
10
11
12
13
14
15
If the value of the EXTERNAL
was set to "ferrari", then when a user chooses the My car
option, the variable carSelection
will be set with the value of the variable usersCar
which is "ferrari"
# Scenario Flow
UPIL scenarios have a simple structure. DIALOG
, and RUN
entities are two of the three entities that can exist at the top level of a document (EXTERNAL
being the third).
DIALOG
is a container for other entities. The UPIL engine runs entities from top to bottom inside of a DIALOG
. However the order of DIALOG
entities inside of a scenario doesn't matter. Instead, DIALOG
to start a scenario at is specified by the scenario writer with the RUN
command. After that, other DIALOG
entities will only be used if they are referred to by embed ...dialogName
calls.
# Dialog
A DIALOG
is a container that most entities must be wrapped in. The UPIL Engine runs the steps of a scenario in the order that they appear in a DIALOG
:
DIALOG main
TEMPLATE "I'm first"
TEMPLATE "I'm second"
TEMPLATE "I'm third"
/DIALOG
RUN main
2
3
4
5
6
7
8
A DIALOG
can hold TEMPLATE
, SELECT
, MULTI_SELECT
, IF/ELIF/ELSE
, ACTION
, and even other DIALOG
entities.
# Dialog Embedding
Using the ...<dialogLabel>
sytax, a DIALOG
can embed another DIALOG
inside of itself:
DIALOG main
TEMPLATE "OK lets start!"
...getUserName
TEMPLATE "Nice to meet you ${name}"
/DIALOG
DIALOG getUserName
TEMPLATE
"What is your name?"
>>name
/TEMPLATE
/DIALOG
RUN main
2
3
4
5
6
7
8
9
10
11
12
13
14
A DIALOG
can be embedded in as many other DIALOG
s as you want. The order of DIALOG
s don't matter.
# Run
The RUN
command specifies the DIALOG
to start the scenario at.
The below two examples demonstrate how changing the RUN
command changes which DIALOG
is processed by the Engine:
Start at dialog A
:
DIALOG B
TEMPLATE
"Hi from B"
/TEMPLATE
/DIALOG
DIALOG A
TEMPLATE
"Hi from A"
/TEMPLATE
/DIALOG
RUN A
2
3
4
5
6
7
8
9
10
11
12
13
14
Start at dialog B
:
DIALOG B
TEMPLATE
"Hi from B"
/TEMPLATE
/DIALOG
DIALOG A
TEMPLATE
"Hi from A"
/TEMPLATE
/DIALOG
RUN B
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Scenario Logic
UPIL contains several features that can be used to conditionally hide or show parts of a scenario. This allows you to dynamically adjust a scenario to user-input and/or external data.
# Conditional logic
UPIL has boolean IF
, ELIF
, and ELSE
entities. You can use conditional logic to make scenarios that respond dynamically to user-input and external data:
DIALOG main
SELECT
"Please choose your favorite color"
-("Red", "red")
-("Blue", "blue")
-("Green", "green")
-("Other", "other")
>>color
/SELECT
IF color=="red"
TEMPLATE "You must like roses!"
ELIF color=="blue"
TEMPLATE "You must like the ocean!"
ELIF color=="green"
TEMPLATE "You must like nature!"
ELSE
DIALOG
TEMPLATE
"Okay, what other color do you like?"
>>otherColor
/TEMPLATE
TEMPLATE "I see. We'll have to think of a new witty response for when someone chooses '${otherColor}'!"
/DIALOG
/IF
/DIALOG
RUN main
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# Boolean Expressions
UPIL allows you to use boolean expressions with IF
/ELIF
/ELSE
conditional logic to hide/show parts of a scenario, or to choose which 'branch' to take.
# Boolean comparators
The following comparators can be used with mixes of variables and literals:
==
, >
, <
, >=
, <=
# Examples
currentTemp >= 25
True if the variable currentTemp
is greater or equal to the number 25
.
car == "toyota"
True if the variable car
is equal to the string toyota
# Boolean operators
The following logical operators allow you to combine several boolean statements together:
AND
, NOT
, OR
, ()
# Examples
Example using AND
, OR
, and ()
:
((currentTemp >= 25 AND hour > 100) OR hello == "GREAT") AND hi == "Something"
Using OR
and NOT
:
hour > 100 OR NOT (currentTemp >= 25)
# Application communication
UPIL includes three features to make it easy to communicate between a scenario and an application which utilizes UPIL: EXTERNAL
and ACTION
entities, and entity labels. These features allow a scenario writer to use high-level concepts, which a developer can then hook up to arbitrarily complex implementations. Ideally even after the implementation has been created, the scenario writer can freely update their scenario without having to rely on a developer to update the implementation.
# External
The EXTERNAL
entity allows a scenario writer to request that the implementation prepare a variable with some data so that the scenario may make use of it.
Basic example:
EXTERNAL currentTime
DIALOG A
TEMPLATE
"The current time is ${currentTime}"
/TEMPLATE
/DIALOG
RUN A
2
3
4
5
6
7
8
9
10
This example registers a hook in the Engine that a developer must use to prepare data that a scenario requires. This example's implementation saves either 'cloudy', 'sunny', or 'rainy' to the weather
variable before the scenario begins:
EXTERNAL weather
DIALOG weatherExplanation
TEMPLATE "The weather is currently ${weather}"
IF weather=="cloudy"
TEMPLATE "It's going to be cool all day"
ELIF weather=="sunny"
TEMPLATE "Pack your sunscreen it's going to be hot!"
ELIF weather=="rainy"
TEMPLATE "Looks like you're going to need an umbrella today!"
ELSE
TEMPLATE "I can't even explain this weather..."
/IF
/DIALOG
RUN weatherExplanation
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Action
An ACTION
allows scenario writers to request that a side-effect happens in the implementation. This can include saving data, sending messages such as emails or push notifications, or making calls to external services. Actions can be used to make a call with variables gathered by the script, and can save the result in a variable itself. An ACTION
must be placed inside of a DIALOG
. When the Engine reaches an ACTION
in the scenario, it tells the implementation about it. The implementation can decide whether or not to delay the scenario until the ACTION
is complete. An example usecase for an ACTION
is sending an email or a push message at a specific point in the scenario.
DIALOG rainy
TEMPLATE "Looks like you're going to need an umbrella today!"
SELECT
"Do you want me to call a taxi for you?"
-("Yes", true)
-("No", false)
>>callTaxi
/SELECT
IF callTaxi==true
DIALOG
TEMPLATE "Okay, I'll get right on that!"
ACTION callTaxi
/DIALOG
ELSE
TEMPLATE "Drive safe!"
/IF
/DIALOG
RUN rainy
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
DIALOG rainy
TEMPLATE
"What word would you like to look up?"
>>lookupWord
/TEMPLATE
ACTION lookupDefinition
{
lookupWord
}
>>wordDefinition
/ACTION
IF wordDefinition == null
TEMPLATE "Sorry, I could not find a definition for '${lookupWord}'"
ELSE
TEMPLATE "The definition of ${lookupWord} is '${wordDefinition}'"
/IF
/DIALOG
RUN rainy
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Labels
Labels are required in many cases, such as when using an ACTION
entity or when referring to a DIALOG
from a RUN
entity. There are many cases however where optional labels are useful as well, for communicating with an underlying implementation.
Labels can be applied to a TEMPLATE
, SELECT
, or MULTI_SELECT
entity in order to override the default behavior for a specific entity. For instance, instead of just showing text, an application may want to substitute in a complex widget such as a map, or a data table. By agreeing on a label name and overriding an entity when that name appears, scenario writers and developers can work together to create much more complex interactions than is possible with just exchanging text.
Here is an example where the implementation is waiting to override an entity with the label brandImage
with an embedded image of their brand in addition to the text:
DIALOG welcome
TEMPLATE "Welcome to our site!"
TEMPLATE brandImage
"I'll be guiding you through our options today"
/TEMPLATE
/DIALOG
RUN welcome
2
3
4
5
6
7
8
9
# Variables
Variables are where user input and input from EXTERNAL
entities are stored.
Example variable called name
:
TEMPLATE
"What is your name?"
>>name
/TEMPLATE
2
3
4
All variables are stored in a global namespace. This means if a single variable name is used multiple times, it will be overwritten each time. This also means that if a DIALOG
is called multiple times from different parts of a scenario, variables created inside of it will be overwritten each time they are set.
Example of variable someVariable
being overwritten:
DIALOG varTest
TEMPLATE
"What is your favorite color?"
>>someVariable
/TEMPLATE
TEMPLATE
"What is your favorite fruit?"
>>someVariable
/TEMPLATE
TEMPLATE
"What is your hobby?"
>>someVariable
/TEMPLATE
TEMPLATE "The value of 'someVariable' is ${someVariable}"
/DIALOG
RUN varTest
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18