Generated on 29 Apr, 2022
by Siwei Liu
Reference:
N: variable name V: variable reference ($VR) or value (int|str|[]|{}) S: list|str $VR M: map $VR L: label F: function name
Runtime Script is a tiny programming language I created for fun since early 2019. Its syntax is assembly-like and greatly inspired by the game Shenzhen IO. Runtime Script is written in Javascript so that it can be parsed and executed directly in the browser.
Using Runtime Script, you can develop mini games (e.g. Flappy Bird), solve algorithm problems (e.g. Selection Sort), build wedgets (e.g. Digital Clock), and do a lot more. (More examples here)
Just like any other programming language, the first program we are going to try is showing a Hello World
message.
Click the Run
button below to run the program.
In the embedded editor above, you can write your program on the left and see the output of your program on the right after clicking the Run
button.
To run the program one more time, just click the Run
button again after the previous execution is finished.
To clear the console contents, you can click the console panel to focus on it, then type clear
and press Enter
key.
Let's get back to the program itself. The above Hello World
program has only one-line code, which contains a keyword prt
and a quoted string 'Hello World'
.
prt 'Hello World!'
In Runtime Script, we call such a line of code a statement
.
Each statement has an command keyword, like prt
in this example, and an arbitrary number of arguments. All the keywords and arguments are separated by spaces.
The first line in the above example is a comment, it is for your notation purpose and simply ignored by the evaluator. A comment starts with a slash (/
), it can be after a statement with the same line or occupy the whole line.
To declare a variable, we use the let
keyword, followed by the variable name and its value.
let N V
A dollar sign ($
) should be prepended to the variable name when it is referenced.
In the above example, we firstly create a new variable called x
with an initial value of 5
, then print x
.
Then we set a new value 'abc'
, which is a string, to the variable x
and print it again.
In Runtime Script, there are only two primitive data types, i.e. integer (int
) and string (str
).
Strings are values surrounded by single quotation marks ('
).
Besides, there are another two advanced data types, list
and map
, and details about these two will be explained in the Data Structure section.
We can check a variable or value's data type by using the typ
command.
typ N V
Also, we can convert integers to strings or strings to integers, using str
and int
respectively.
int N V
str N V
Runtime Script supports five basic arithmetic operations, namely addition (add
), subtraction (sub
), multiplication (mul
), division (div
), and modulo (mod
).
add N V V
sub N V V
mul N V V
div N V V
mod N V V
Let's take addition as an example, the sum of the two values V V
is assigned to the variable N
, the variable N
will be created if it has not been defined.
The div
command works as a floor division, thus the division result is always an integer.
Play around with the following examples to get familiar with these arithmetic operations.
Moreover, the argument can be non-integer for the following cases:
1. add
two strings to concatenate them
2. add
a string/integer to an integer/string to concatenate them
3. mul
a string by an integer to repeat the string certain times
4. add
$nil
with an integer will convert this integer to a character (Decimal to ASCII)
5. sub
a character string by $nil
will convert this character to an integer (ASCII to Decimal)
In Runtime Script, you can insert labels to any places in your program and jump to a specific label using the jmp
command.
jmp L
A label is a line starts with a hashtag #
.
In the following example, the line prt 'skipped'
is skipped because of jumping to the "continue" label.
Four other jump commands only jump when a certain condition is true.
jeq V V L
jne V V L
jlt V V L
jgt V V L
jeq
: jump if V1 equals V2 jne
: jump if V1 is not equal to V2 jlt
: jump if V1 is less than V2 jgt
: jump if V1 is greater than V2 The above example demonstrates printing and incrementing i
from 0 to 4.
Two container data structures are provided in Runtime Script, i.e. list
and map
.
The literal []
represents an empty list. Usually, it is used when defining a new list.
Defining a non-empty list is not supported.
There are three commands for list operations:
psh S V [V..]
pop S N
pol S N
get S V N
put S V V
psh
for appending one or multiple values to the end to the list, pop
for extracting the last item from the list, and pol
for extracting the first item from the list.
pop
orpol
from an empty list will result in a$nil
, which represents an empty value.
List commands also work on strings. We can regard a string as a list and each character is an item in this list.
pop
orpol
from an empty string will result in an empty string (''
).
Indexing on lists is supported.
The literal {}
represents an empty map.
There are two basic commands, put
and get
, for adding a key-value pair and getting a value by its key respectively.
Besides, key
gets the list of keys in the map, and del
can delete a key-value pair from the map.
put M V V
get M V N
key M N
del M V
The keys are always strings, and the values can be any data types.
If you put a key-value pair where the key already exists in the map, the old value will be replaced with the new one.
If the key in the get
statement does not present in the map, a $nil
value will be returned.
We can iterate the elements in a list or the keys in a map using for
and nxt
.
for N V
nxt
If we try to iterate an integer, then it will loop through the integer from 0 to the given integer.
Besides, the for loops can be nested.
Do not terminate a
for
loop before it finishes.
To get the length of list, string or the number of entries in a map, we can use the len
command.
len V N
Get a user input string from the console.
inp N
Pause the program for a certain number of milliseconds.
slp V
In the above example, the program is paused for one second before printing the 'Bye' message.
In the following example, we are going to "slow-print" the hello world message.
You may find that the first prt
has two arguments, the first one is the content to be printed, while the second one is the terminator character, which is optional and is a newline character by default.
In the above example, we are trying to print each character in the same line, thus we indicate the terminator as an empty string.
Get a random integer between two integers, where the ending integer is not included.
rnd N V V
Get the system date or time.
tim N year|month|date|day|hour|minute|second|milli|now
Use tim N now
to get the current timestamp in millisecond.
There is a special value, $lastkey
, which records the user's last pressed key code.
You can check a specific key's code here.
Parsing strings to lists or maps could be tedious, no worries, there is an command for it.
Runtime Script natively supports a canvas for displaying graphics. The default canvas is a 24-by-24 pixel matrix.
You can find there is a black area on the right of the above editor. After clicking the run
button, you will see a white dot drawn on the top-left corner.
The origin of the canvas is at the top-left, and column/row numbers are zero-based.
For instance, drw 0 2 1
means filling the dot on column 0 (1st column) row 2 (3rd row) with white (1
).
The supported commands for canvas operations are:
clr V*
drw V V V
pxl N V V
clr
: clear the canvas, in other words, fill the whole canvas with black. The optional parameter is the dimension of the canvas, and its default value is 24drw
: fill the pixel at (V1, V2) with color V3pxl
: get the color of the pixel (V1, V2)The canvas and console can work together, in the following example, it prints three dots on the canvas with a 0.2-second interval, then prints the 'Hello World!' in the console.
Runtime Script canvas suppots 16 colors.
Runtime Script also has some advanced commands to mimic some high-level programming language statements, such as if-else and functions. These commands can make it more convenient to write programs, but we should use them with caution.
Indentations in Runtime Script are only for readability, they do not affect the execution.
Executing certain lines of statements depends on the comparison result of two values.
ife V V
ifg V V
els
fin
ife
: if V1 equals V2, execute the statements below until els
or fin
encounteredifg
: similar to ife
, but check if V1 is greater than V2 insteadels
: (optional) if the above condition is false, execute the statements below until fin
encounteredfin
: the end of if-elseIf-else is a convenient way to write condition checks, it may save your time writing convoluted codes with jumps and labels.
The following program checking the equality of two numbers by using if-else
is equivalent to
Nested if-else is supported.
Functions define blocks of statements for code reuse.
def F
ret V*
end
cal F
def
: the head of a function definition with a nameret
: jump to the line below the previous function call. (The returned value is optional)end
: the end of the function definition, jump to the line below the previous function callcal
: jump to the function head by nameIn the example below, a 'random' function is defined and then invoked twice.
You can pass values as parameters to the function you are calling, and get these values in the function by indexing ($0, $1, $2 and so on).
The ret
command can terminate a function before reaching the end of it. Besides, it can optionally return a value to the caller's layer. The returned value is stored in $ret
.
Function parameters are read-only. Assign their values to local variables if you want to modify them.
Variables defined outside functions are called global variables, you can access or modify global variables in any functions.
Meanwhile, you can also define function scoped (local) variables, which is only accessible within the function where the variable is defined. A local variable must start with an underscore (_
).
Like local variables, labels defined in functions are invisible outside. And it is not allowed to jump to a golbal label from a function body.
You can invoke a function inside a function.
Recursion is supported. The following program demonstrates the recursive version of calculating factorials.