Built-ins
Built-ins in Evy are pre-defined functions and events that allow for user interaction, graphics, animation, mathematical operations, and more.
Functions are self-contained blocks of code that perform a specific task. Events are notifications that are sent to a program when something happens, such as when a user moves the mouse or presses a key.
For a more formal definition of the Evy syntax, see the Language Specification, and for an intuitive understanding see syntax by example.
#Input and Output
#print
print
prints the arguments given to it to the output area. It separates them
by a single space and outputs a newline character at the end.
Example
print "Hello"
print 2 true "blue"
print "array:" [1 2 3]
print "map:" {name:"Scholl" age:21}
Output
Hello
2 true blue
array: [1 2 3]
map: {name:Scholl age:21}
Reference
print a:any...
The print
function prints its arguments to the output area, each separated by
a single space and terminated by a newline character. If no arguments are provided it only
prints the newline character.
The backslash character \
can be used to represent special characters in
strings. For example, the \t
escape sequence represents a tab character, and
the \n
escape sequence represents a newline character. Quotes in string
literals must also be escaped with backslashes, otherwise they will be interpreted as the
end of the string literal. For example:
print "Here's a tab: 👉\t👈\nShe said: \"Thank you!\""
Output
Here's a tab: 👉 👈
She said: "Thank you!"
In a browser environment print
outputs to the output area. When running Evy
from the command line interface, print
prints to standard out.
#read
read
reads a line of input from the user and returns it as a string. The
newline character is not included in the returned string.
Example
name := read
print "Hello, "+name+"!"
Input
Mary Jackson
Output
Hello, Mary Jackson!
Reference
read:string
The read
function returns a string that contains the line of input that the
user entered up until, excluding the newline character. It is a blocking functions, which
means that it will not return until the user has entered a line of input and pressed the
Enter key.
In a browser environment read
reads from the text input area. When running
Evy from the command line interface, read
reads from standard in.
#cls
cls
clears the output area of all printed text.
Example
print "Hello"
sleep 1
cls
print "Bye"
Output
Bye
Reference
cls
The cls
function clears all text output. In a browser environment
cls
clears the output area. When running Evy from the command line interface,
cls
clears the terminal, similar to the Unix clear
or Windows
cls
commands.
#printf
printf
stands for print formatted.
printf
prints its arguments to the output area according to a
format string. The format string is the first argument, and it contains
specifiers. Specifiers start with a percent sign %
. They
tell the printf
function how and where to print the remaining arguments
inside the format string. The rest of the format string is printed to the output area
without changes.
Here are some valid specifiers in Evy:
Specifier | Description |
---|---|
%v |
the argument in its default format |
%q |
a double-quoted string |
%% |
a percent sign % |
Example
printf "The tank is 100%% full.\n\n"
weather := "rainy"
printf "It is %v today.\n" weather
rainfall := 10
printf "There will be %vmm of rainfall.\n" rainfall
unicorns := false
printf "There will be unicorns eating lollipops: %v.\n\n" unicorns
quote := "Wow!"
printf "They said: %q\n" quote
printf "Array: %v\n" [1 2 3]
printf "Map: %v\n" {a:1 b:2}
Output
The tank is 100% full.
It is rainy today.
There will be 10mm of rainfall.
There will be unicorns eating lollipops: false.
They said: "Wow!"
Array: [1 2 3]
Map: {a:1 b:2}
Reference
printf format:string a:any...
The printf
function prints its arguments to the output area according to the
format string that is the first argument. The
specifiers that start with %
and are contained in the format
string are replaced by the remaining arguments in the given order. For example, the
following code
printf "first: %s, second: %s" "A" "B"
prints
first: A, second: B
.
Full list of valid specifiers in Evy:
Specifier | Description |
---|---|
%v |
the argument in a default format |
%t |
the word true or false |
%f |
decimal point (floating-point) number, e.g. 123.456000 |
%e |
scientific notation, e.g. -1.234456e+78 |
%s |
string value |
%q |
a double-quoted string |
%% |
a literal percent sign % ; consumes no value |
If the arguments for the %s
, %q
, %f
,
%e
, and %t
specifiers do not match the required type, a panic
will occur.
The width and precision of a floating-point number can
be specified with the %f
and %v
format specifiers.
- Width is the number of characters that will be used to print the number. If the width is not specified, it will be calculated based on the size of the number. It can be useful for padding and aligned output.
-
Precision is the number of decimal places that will be displayed. If the precision is
not specified, it will be set to 6 for
%f
.
Here is a table that shows the different ways to specify the width and precision of a floating-point number:
Verb | Description |
---|---|
%f |
default width, default precision |
%7f |
width 7, default precision |
%.2f |
default width, precision 2 |
%7.2f |
width 7, precision 2 |
%7.f |
width 7, precision 0 |
If the width/precision is preceded by a -
, the value is padded with spaces on
the right rather than the left. If it is preceded by a 0, the value is padded with leading
zeros rather than spaces.
The width, precision and alignment prefix (-
or 0
) can be used
with all valid specifiers. For example:
printf "right: |%7.2f|\n" 1
printf "left: |%-7.2v|\n" "abcd"
printf "zeropad:|%07.2f|\n" 1.2345
Output
right: | 1.00|
left: |ab |
zeropad:|0001.23|
#Types
#len
len
returns the number of characters in a string, the number of elements in
an array or the number of key-value pairs in a map.
Example
l := len "abcd"
print "len \"abcd\":" l
l = len [1 2]
print "len [1 2]:" l
l = len {a:3 b:4 c:5}
print "len {a:3 b:4 c:5}:" l
Output
len "abcd": 4
len [1 2]: 2
len {a:3 b:4 c:5}: 3
Reference
len:num a:any
The len
function takes a single argument, which can be a string, an array, or
a map. If the argument is a string, len
returns the number of characters in
the string. If the argument is an array, len
returns the number of elements
in the array. If the argument is a map, len
returns the number of key-value
pairs in the map. If the argument is of any other type, a panic will occur.
#typeof
typeof
returns the type of the argument as string value.
Example
a:any
a = "abcd"
t := typeof a
print "typeof \"abcd\":" t
t = typeof {kind:true strong:true}
print "typeof {kind:true strong:true}:" t
t = typeof [[1 2] [3 4]]
print "typeof [[1 2] [3 4]]:" t
t = typeof [1 2 true]
print "typeof [1 2 true]:" t
print "typeof []:" (typeof [])
Output
typeof "abcd": string
typeof {kind:true strong:true}: {}bool
typeof [[1 2] [3 4]]: [][]num
typeof [1 2 true]: []any
typeof []: []any
Reference
typeof:string a:any
The typeof
function takes a single argument, which can be of any type. The
function returns a string that represents the type of the argument. The string returned by
typeof
is the same as the type in an Evy program, for example
num
, bool
, string
, []num
,
{}[]any
. For an empty composite literal, typeof
returns
[]
or {}
as it can be matched to any subtype, e.g.
[]
can be passed to a function that takes an argument of []num
,
or []string
.
#Map
#has
has
returns whether a map has a given key or not.
Example
map := {a:1}
printf "has %v %q: %t\n" map "a" (has map "a")
printf "has %v %q: %t\n" map "X" (has map "X")
Output
has {a:1} "a": true
has {a:1} "X": false
Reference
has:bool map:{} key:string
The has
function takes two arguments: a map and a key. It returns true if the
map has the key, and false if the map does not have the key. The map can be of any value
type, such as {}num
or {}[]any
and the key can be any string.
#del
del
deletes a key-value entry from a map.
Example
map := {a:1 b:2}
del map "b"
print map
Output
{a:1}
Reference
del map:{} key:string
The del
function takes two arguments: a map and a key. It deletes the
key-value entry from the map if the key exists. If the key does not exist, the function
does nothing. The map can have any value type, and the key can be any string. It is safe
to delete values from the map with del
while iterating with a
for … range
loop.
#Program control
#sleep
sleep
pauses the program for the given number of seconds.
sleep
can be used to create delays in Evy programs. For example, you could
use sleep to create a countdown timer.
In the browser runtime sleep
pauses a
minimum of 1 millisecond.
Example
print "2"
sleep 1
print "1"
Output
2
1
Reference
sleep seconds:num
The sleep
function pauses the execution of the current Evy program for at
least the given number of seconds. Sleep may also pause for a fraction of a second, e.g.
sleep 0.1
.
#exit
exit
terminates the program with the given status code.
Example
input := "not a number"
n := str2num input
if err
print errmsg
exit 1
end
print n
Output
str2num: cannot parse "not a number"
#panic
panic
prints the given error message and terminates the program immediately.
It is used to report unrecoverable errors.
Example
scale := -5
if (scale) <= 0
panic "scale must be positive"
end
Output
line 4 column 5: scale must be positive
Reference
panic msg:string
The panic
function takes a single argument, which is the error message that
the program will print before it terminates with exit status 1.
#test
test
is used to check if a condition is true or two values –
want
and got
– are the same. If the condition is not true or the
two values are not the same, the program will print the failed test and terminate with
exit status 1.
test
optionally takes a message or a format string with arguments to print
along with the failed test as a third and following arguments:
Example
answer := 6 * 9
test 42 answer "answer is 42 not %v" answer
Output
❌ 1 failed test
✔️ 0 passed tests
line 2 column 9: failed test: want != got: 42 != 54 (answer is 42 not 54)
Reference
test cond:bool
test want:any got:any [msg:string [argsany...]]
The test
function takes either a single boolean argument
cond
and ensures it is true
, or two arguments
want
and got
, in that order, and ensures they are the same.
In the case of the single argument, the argument must be of type bool
.
test
verifies that this argument has the value true
. If
cond
is false, test
terminates the program execution and prints
the failed test.
In the case of two arguments, want
and got
,
test
verifies the arguments are the same. If they are not the same
test
terminates the program execution and prints the failed test.
Sameness of want
and got
means either
want == got
or want
and got
are composite values,
arrays or maps, containing the same values. want
can be of a more
specific type than got
as long as their values are the same. For
example, the following test holds true even though want
is of type
[][]num
and got
is of type []any
.
got:[]any
got = [[1] [2 3]]
test [[1] [2 3]] got
In the case of three arguments, the third argument is a message of type
string
that is printed if the test fails.
In case of four or more arguments, the third argument is a format string with
specifiers. The remaining arguments are the arguments are used to replace these
specifiers, see sprintf
for details on formatting.
This means the following two tests are equivalent.
val := 2
test 1 val "val is %v" val
test 1 val (sprintf "val is %v" val)
Using test
with four or more arguments is a convenience compared to adding an
inline call to sprintf
.
#Conversion
#str2num
str2num
converts a string to a number. If the string is not a valid number,
it returns 0
and sets the global err
variable to
true
.
Example
n:num
n = str2num "1"
print "n:" n "err:" err
n = str2num "NOT-A-NUMBER"
print "n:" n "err:" err
Output
n: 1 err: false
n: 0 err: true
Reference
str2num:num s:string
The str2num
function converts a string to a number. It takes a single
argument, which is the string to convert. If the string is a valid number, the function
returns the number. Otherwise, the function returns 0 and sets the global
err
variable to true
. For more information on err
,
see the Recoverable Errors section.
#str2bool
str2bool
converts a string to a boolean. If the string is not a valid
boolean, it returns false
and sets the global err
variable to
true
.
Example
b:bool
b = str2bool "true"
print "b:" b "err:" err
b = str2bool "NOT-A-BOOL"
print "b:" b "err:" err
Output
b: true err: false
b: false err: true
Reference
str2bool:bool s:string
The str2bool
function converts a string to a bool. It takes a single
argument, which is the string to convert. The function returns true
if the
string is equal to "true"
, "True"
,
"TRUE"
, or "1"
, and false
if
the string is equal to "false"
, "False"
,
"FALSE"
, or "0"
. The function returns
false
and sets the global err
variable to true
if
the string is not a valid boolean. For more information on err
, see the
Recoverable Errors section.
#Errors
Evy has two types of errors: parse errors and run-time errors.
-
parse errors are reported before the program is executed. They report
errors with the syntax, such as a missing closing quote for
print "abc
, an illegal character, such as#
, or type errors, such asmin "a" "b"
. - Run-time errors only occur if there are no parse errors and the code path causing the error is executed.
For example, the following code will sometimes cause a run-time error:
n:num
if (rand1) < 0.5
n = str2num "not-a-number"
else
n = str2num "5"
end
print "n:" n "error:" err
Half the time, the program above will cause a run-time error and print
n: 0 error: true
. The other half of the time, no error will occur and the
program will print n:5 error:false
.
Evy has two types of run-time errors: panic and error.
- A panic is non-recoverable. It causes the program to exit immediately.
- An error is recoverable. The program can continue running after the error is handled.
#Panic
A panic causes the program to exit immediately and print an error message. Panics typically occur when the program encounters a situation that it cannot handle, such as trying to access an element of an array that is out of bounds. Panics cannot be intercepted by the program, so it is important to take steps to prevent them from occurring in the first place.
One way to do this is to use guarding code, which is code that checks for potential errors and takes steps to prevent them from occurring. For example, guarding code could be used to check the length of an array before trying to access an element to avoid an out of bounds error. If the access index is out of bounds, the guarding code could report the error.
Here is an example of a panic:
arr := [0 1 2]
i := 5 // e.g. user input
print arr[i] // out of bounds
print "This line will not be executed"
This code will cause a panic because the index 5 is out of bounds for the array
arr
. The program will exit with the error message
line 3: panic: index out of bounds: 5
If you want your own code to panic, you can use the built-in panic
function.
This is typically used to highlight mistakes or bugs in your program, such as invalid
function arguments or conditions that should never occur. The panic
function
exits your program immediately, so it should only be used when it is clear that the
program cannot continue. For more information, see the Panic section
under Program Control above.
#Recoverable Errors
The global err
variable is used to indicate whether a recoverable error has
occurred. The global errmsg
variable stores a detailed message about the
error that occurred.
Recoverable errors are caused by code that could not be prevented from running, such as
converting a user input string to a number if the string is not a number. This recoverable
error will set the global err
variable to true
and the program
will continue executing. If there is no error, err
is set to
false
.
The global errmsg
variable stores a detailed message about the error which is
set alongside err
. errmsg
is set to the empty string
""
if no error has occurred. If an error does occur,
errmsg
is set to a message that describes the error.
When a function that could potentially cause an error finishes executing without an error,
the err
variable is reset to false
and the
errmsg
variable is set to the empty string. This is done even if the
err
variable was previously set to true
or the
errmsg
variable was not empty. Therefore, it is up to the program to check
the err
variable after any possible error occurrence.
Here is an example of a recoverable error:
n := str2num "NOT A NUM"
print "num:" n
print "err:" err
print "errmsg:" errmsg
Output
num: 0
err: true
errmsg: str2num: cannot parse "NOT A NUM"
If you want your own code or function to cause a recoverable error, follow the convention
of setting the err
variable to true
and the
errmsg
variable to a message describing the error in the error case. In the
non-error case, make sure to set the err
variable to false
.
#String
#sprint
sprint
stands for print to string.
It returns a string representation of the arguments given to it. It separates them by a
single space. Unlike print
, there is no newline added to the end.
Example
s := sprint "a" [true] {a:1 b:2}
printf "%q\n" s
printf "%q\n" (sprint)
Output
"a [true] {a:1 b:2}"
""
Reference
sprint:string a:any...
The sprint
function takes any number of arguments and returns a string that
represents them, separated by a single space. The arguments can be of any type, including
strings, numbers, booleans, and maps. Unlike the print
function, there is no
newline added to the end of the string.
#sprintf
sprintf
stands for print formatted to string.
sprintf
returns a string representation of its arguments according to a
format string. Formatting in sprintf
and
printf
work the same way, see printf
.
Example
s := sprintf "%10q: %.f" "val" 123.45
print s
Output
"val": 123
Reference
sprintf:string format:string a:any...
The sprintf
function returns a string representation of its arguments
according to a format string. The format string controls how the
arguments are formatted. The sprintf
function works the same way as the
printf
function, and the formatting syntax is the same, see
printf
.
#join
join
concatenates the elements of an array of values into a single string,
with the given separator string placed between elements. Any elements of the array that
are not strings are formatted as strings.
Example
s := join ["a" "b" "c" 1 3.141592654 true] ", "
print s
Output
a, b, c, 1, 3.141592654, true
Reference
join:string elems:[]any sep:string
The join
function takes two arguments: an array of any and a separator
string. The array of any is the list of elements to be concatenated. The separator string
is the string that will be placed between elements in the resulting string. Values of the
array that are not strings are formatted as strings.
The join
function returns a single string that is the concatenation of the
elements in the list of any, with the separator string placed between elements.
#split
split
splits a string into a list of substrings separated by the given
separator. The separator can be any string, including the empty string.
Example
print (split "a,b,c" ",")
print (split "a,b,c" ".")
print (split "a,b,c" "")
Output
[a b c]
[a,b,c]
[a , b , c]
Reference
split:[]string s:string sep:string
The split
function takes two arguments: the string to be split and the
separator string. The string to be split is the string that will be split into substrings.
The separator string is the string that will be used to split the string.
The split
function returns a list of substrings. The list of substrings
contains all of the substrings of the original string that are separated by the separator
string.
If the string does not contain the separator, the split
function returns an
array of length 1 containing the original string.
If the separator is the empty string, the split
function splits the string
after each character (UTF-8 sequence).
If both the string and the separator are empty, the split
function returns an
empty list.
#upper
upper
returns a string with all lowercase letters converted to uppercase.
Example
s := upper "abc D e ü"
print s
Output
ABC D E Ü
Reference
upper:string s:string
The upper
function takes a single argument: the string to be converted to
uppercase. The function returns a new string with all lowercase letters converted to
uppercase. All other characters are left unchanged.
The upper
function uses the Unicode character database to determine which
characters are lowercase and their equivalent uppercase form.
#lower
lower
returns a string with all uppercase letters converted to lowercase.
Example
s := lower "abc D e ü"
print s
Output
abc d e ü
Reference
lower:string s:string
The lower
function takes a single argument: the string to be converted to
lowercase. The function returns a new string with all uppercase letters converted to
lowercase. All other characters are left unchanged.
The lower
function uses the Unicode character database to determine which
characters are uppercase and their equivalent lowercase form.
#index
index
returns the position of a substring in a string, or -1 if the substring
is not present.
Example
n := index "abcde" "de"
print n
Output
3
Reference
index:num s:string sub:string
The index
function finds the index of a substring sub
in a
string s
. It returns the index of the first occurrence of a
sub
within s
, or -1 if the substring is not present.
#startswith
startswith
tests whether a string begins with a given prefix.
Example
b := startswith "abcde" "ab"
print b
Output
true
Reference
startswith:bool s:string prefix:string
The startswith
function tests whether the string s
begins with
prefix
and returns true
if s
starts with
prefix
, false
otherwise.
#endswith
endswith
tests whether a string ends with a given suffix.
Example
b := endswith "abcde" "ab"
print b
Output
false
Reference
endswith:bool s:string suffix:string
The endswith
function tests whether the string s
ends with
suffix
and returns true
if s
ends with
suffix
, false
otherwise.
#trim
trim
removes leading and trailing characters from a string.
Example
s := trim ".,..abc.de." ".,"
print s
Output
abc.de
Reference
trim:string s:string cutset:string
The trim
function removes any characters in cutset
from the
beginning and end of string s
. It returns a copy of the resulting string.
#replace
replace
replaces all occurrences of a substring with another substring in a
string.
Example
s := replace "abc123xyzabc abc" "abc" "ABC"
print s
Output
ABC123xyzABC ABC
Reference
replace:string s:string old:string new:string
The replace
function replaces all occurrences of the substring
old
in the string s
with the substring new
.
#repr
repr
returns a string representation of its arguments, typically as valid,
formatted Evy code. The notable exception are maps with keys that could not be used in a
map literal.
Example
s := repr 1 "abc"
print s
Output
1 "abc"
Reference
repr:string a:any...
The repr
function returns a string representation of its arguments, typically
as valid, formatted Evy code. The notable exception are maps with keys that could not be
used in a map literal.
Type | Representation |
---|---|
num |
as is |
bool |
as is |
string |
double-quoted with internal quotes escaped |
[] ... |
enclosed in square brackets, details below |
{} ... |
enclosed in curly braces, details below |
The elements of an array are printed according to repr
and space-separated.
The key-value pairs of a map are space-separated, with keys separated from values by
:
. Keys are printed without quotes if they are valid identifiers or Evy
keywords, and surrounded by quotes with escaped internal quotes if not. Values are printed
according to repr
.
#Random
#rand
rand
returns a random, non-negative integer less than the argument.
Example
print (rand 3)
print (rand 3)
Sample output
2
0
Reference
rand:num n:num
The rand
functions returns, a non-negative pseudo-random integer number in
the half-open interval [0,n)
. A panic occurs for n <= 0
.
#rand1
rand1
returns a random, non-negative floating point number less than 1.
Example
print (rand1)
print (rand1)
Sample output
0.7679753163102002
0.6349044894123325
Reference
rand1:num
The rand1
function returns a pseudo-random floating point number in the
half-open interval [0.0,1.0)
.
#Math
#min
min
returns the smaller of the two given numbers.
Example
print (min 3 1)
Output
1
Reference
min:num n1:num n2:num
The min
function returns the smaller of the two given number arguments.
#max
max
returns the greater of the two given numbers.
Example
print (max 3 1)
Output
3
Reference
max:num n1:num n2:num
The max
function returns the greater of the two given number arguments.
#abs
abs
returns the absolute value of a number.
Example
print (abs 3)
print (abs -2.5)
Output
3
2.5
Reference
abs:num n:num
The abs
function returns the absolute value of a number, which is its
magnitude without regard to its sign.
#floor
floor
returns the greatest integer value less than or equal to the given
number.
Example
print (floor 2.7)
print (floor 3)
Output
2
3
Reference
floor:num n:num
The floor
function returns the greatest integer value less than or equal to
its number argument n
.
#ceil
ceil
returns the smallest integer greater than or equal to the given number.
Example
print (ceil 2.1)
print (ceil 4)
Sample output
3
4
Reference
ceil:num n:num
The ceil
function returns the smallest integer greater than or equal to its
number argument n
.
#round
round
returns the nearest integer to the given number, rounding half away
from 0.
Example
print (round 2.4)
print (round 2.5)
Sample output
2
3
Reference
round:num n:num
The round
function returns the nearest integer to the given number argument
n
, rounding half away from 0.
#pow
pow
returns the value of the first number raised to the power of the second
number.
Example
print (pow 2 3)
Output
8
Reference
pow:num b:num exp:num
The pow
function returns b
to the power of exp
. The
first number argument b
is the base. The second number argument
exp
is the exponent.
#log
log
returns the logarithm of the given number, to the base of e.
Example
printf "%.2f\n" (log 1)
printf "%.2f\n" (log 2.7183) // e
Output
0.00
1.00
Reference
log:num n:num
The log
function returns the natural logarithm, the
logarithm of the given number argument n
, to the base of e
.
#sqrt
sqrt
returns the square root of the given number.
Example
print (sqrt 9)
Output
3
Reference
sqrt:num n:num
The sqrt
function returns the positive square root of the number argument
n
.
#pi
pi
is a global variable with the value of the mathematical constant
π.
#sin
sin
returns the sine of the given angle in radians.
Example
print (sin 0.5*pi)
Output
1
Reference
sin:num n:num
The sin
function returns the sine of the given angle n
in
radians.
#cos
cos
returns the cosine of the given angle in radians.
Example
print (cos pi)
Output
-1
Reference
cos:num n:num
The cos
function returns the cosine of the given angle n
in
radians.
#atan2
atan2
returns the angle in radians between the positive x-axis and the ray
from the origin to the point x y
.
Example
rad := atan2 1 1
degrees := rad * 180 / pi
printf "rad: %.2f degrees: %.2f" rad degrees
Output
rad: 0.79 degrees: 45.00
Reference
atan2:num y:num x:num
The atan2
function returns the angle in radians between the positive x-axis
and the ray from the origin to the point x y
. More formally, it returns the
arc tangent of y/x
for given arguments y
and x
,
using the signs of the two to determine the quadrant of the return value.
#Graphics
Evy on the web outputs drawing commands to a drawing area called the canvas.
Positions on the canvas are defined by a coordinate system, similar to the Cartesian coordinate system used in mathematics. The horizontal dimension is called the x-axis, and the vertical dimension is called the y-axis.
A point on the canvas is defined by its x and
y coordinates, which are written as x y
. For example, the
point 30 60
has an x-coordinate of 30 and a y-coordinate of 60. It is located
30 units from the left edge of the canvas and 60 units from the bottom edge.
The canvas ranges from coordinates 0 0
to 100 100
. The center of
the canvas has the coordinates 50 50
.
Shapes are drawn on the canvas using a pen. The pen has an
x y
position and a style. The position of the pen is also known as the
current cursor position.
Some graphics functions, like line
, rect
, circle
,
and text
, create shapes on the canvas. Other graphics functions such as
color
, width
, and font
set the style of the pen for
subsequent drawing commands.
#move
move
sets the position of the pen to the given coordinates.
Example
grid
move 30 60
circle 1
Output
Reference
move x:num y:num
The move
function sets the position of the cursor to the given
x
and y
coordinates. The initial cursor position is
0 0
.
#line
line
draws a line from the current position of the pen to the given
coordinates.
Example
The following example draws a triangle.
move 30 20
line 70 20
line 50 50
line 30 20
Output
Reference
line x:num y:num
The line
function draws a line from the current cursor position to the given
x
and y
coordinates. The cursor position is then updated to the
given coordinates, which allows for easy polygon drawing.
#rect
rect
draws a rectangle with the given width and height at the pen's current
position.
Example
grid
move 40 20
rect 10 30
rect 40 20
Output
Reference
rect width:num height:num
The rect
function draws a rectangle with the given width
and
height
at the current cursor position. The cursor position is then updated to
the position that is the width and height away from the current position. In other words,
the opposite corner of the rectangle is at the new cursor position.
#circle
circle
draws a circle with given radius at the pen's current position.
Example
grid
move 50 50
circle 10
Output
Reference
circle radius:num
The circle
function draws a circle with the given
radius
centered at the current cursor position. The cursor position does not
change after drawing a circle.
#color
color
changes the color of the pen. All
CSS (Cascading Style Sheets) color values
are supported. You can start by using the simpler
named CSS colors
, such as "red"
, "darkmagenta"
, and
"springgreen"
.
Example
color "darkmagenta"
rect 20 20
Output
Reference
color c:string
The color
function changes the color of the stroke and the
fill to the given CSS color string c
. Evy supports all
CSS color values, including semi-transparent ones. For example, the following code changes the color to a
shade of red that is 60% opaque: color "rgb(100% 0% 0% / 60%)"
.
Named CSS colors, such as "red"
,
"darkmagenta"
, and "springgreen"
, are a
simpler way of specifying common colors. For a complete list of named CSS colors, see the
Mozilla Developer documentation.
If the color string c
is not recognized as a valid CSS color, the color does
not change. The initial color is "black"
.
#colour
colour
is an alternate spelling of color
. See
color
.
#hsl
hsl
returns a string to be used with the
color
and
clear
functions. The arguments to the
hsl
function are numbers and therefore are more suited to mathematical
manipulation, e.g. to find the complimentary color, create a trail in animations with the
alpha value or create color gradients.
hsl
takes one to four arguments - hue
, saturation
,
lightness
, and alpha
- and returns a
CSS (Cascading Style Sheets) hsl function
string specifying a color.
The hue
argument is required. It is a number from 0 to 360 that represents
the color on the
color wheel:
hue |
color | |
---|---|---|
0 | "red" | |
60 | "yellow" | |
120 | "lime" green | |
180 | "cyan" | |
240 | "blue" | |
300 | "magenta" |
The saturation
, lightness
and alpha
arguments are
optional and must range between 0 and 100 percent if given:
-
saturation
is measure for vibrancy with 100 meaning maximum vibrancy and 0 meaning a shade of grey (default: 100) -
lightness
is measure for brightness with 100 meaning white and 0 meaning black (default: 50) -
alpha
is measure for opacity or transparency with 100 meaning fully opaque and 0 meaning fully transparent (default: 100)
Example
for i := range 360
color (hsl i)
move i/3.6 0
rect 1/3.6 100
end
Output
Reference
hsl:string hue:num [saturation:num [lightness:num [alpha:num]]]
hsl
returns a string to be used with the
color
and
clear
functions. hsl
takes one to four
num
arguments - hue
, saturation
,
lightness
, and alpha
- and returns
string
containing a
CSS hsl function
string.
The hue
value must be between 0 and 360. The saturation
,
lightness
and alpha
values must be between 0 and 100. See the
Mozilla Developer documentation on the
CSS hsl function
for more details.
#width
width
sets the thickness of the lines drawn by the pen.
Example
width 10
line 30 30
width 1
line 60 60
width 0.1
line 90 90
grid
Output
Reference
width n:num
The width
function sets the thickness of the stroke to the
given n
units. The stroke is the visible line that is drawn when using the
line
function or any other shape function after setting
fill "none"
. The initial stroke width it 0.1 units.
#clear
clear
clears the canvas. Optionally, it can take a color argument to clear
the canvas to.
Example
The following example code shows how to draw a magenta square, clear the canvas, and then
draw a blue circle. The final result is a canvas with a blue circle centered at
20 20
. The magenta square is not visible because it has been removed by the
clear
function.
color "darkmagenta"
rect 20 20
clear
color "blue"
circle 5
grid
Output
Reference
clear [c:string]
The clear
function clears the canvas. It can optionally take a color as a
string argument, in which case the canvas will be cleared to that color. If no color is
specified, the canvas will be cleared to "white"
. Initially the
canvas is cleared to "white"
, not
"transparent"
.
#grid
grid
draws a grid on the canvas. The grid is parallel to the x and y axes,
and each grid line is spaced 10 units apart.
Example
grid
Output
Reference
grid
The grid
function draws a grid on the canvas. The grid lines are parallel to
the x and y axes, and each grid line is spaced 10 units apart. The grid lines are 0.1
units thin and have a semi-transparent gray color, with an opacity of 50%. This makes the
grid lines faint enough to be drawn on top of other shapes. The grid lines that go through
the point 50 50
, which is the center of the canvas, are slightly thicker. The
thickness of these grid lines is 0.2 units, which makes it easier to see the center of the
canvas.
The grid
function is a shorthand of the gridn
function with the
arguments 10
and "hsl(0deg 100% 0% / 50%)"
, see
gridn
. It is roughly equivalent to the following Evy code. However, the current color, cursor
position, and line width are not affected by the built-in grid
function.
color "hsl(0deg 100% 0% / 50%)"
for i := range 0 101 10
width 0.1
if i == 50
width 0.2
end
move i 0
line i 100
move 0 i
line 100 i
end
#gridn
gridn
draws a grid on the canvas. The grid is parallel to the x and y axes,
and each grid line is spaced the given number of units apart. The color of the grid is set
to the given color.
Example
gridn 2 "red"
Output
Reference
gridn n:num c:string
The gridn
function draws a grid on the canvas. The grid lines are parallel to
the x and y axes, and each grid line is spaced n
units apart. The color of
the grid is set to the color specified by the string argument c
. The default
line width is 0.1 units. Every fifth grid line is slightly thicker, with a line width of
0.2 units.
The gridn
function is roughly equivalent to the following Evy code, but the
current color, cursor position, and line width are not affected by the built-in
gridn
function.
c := "red"
n := 2
color c
linecnt := 0
for i := range 0 101 n
width 0.1
if linecnt % 5 == 0
width 0.2
end
linecnt = linecnt + 1
move i 0
line i 100
move 0 i
line 100 i
end
#poly
poly
draws polylines and polygons for the given coordinates.
Example
The following code draws a w-shaped red polyline and a yellow triangle.
width 1
color "red"
fill "none"
poly [10 80] [30 60] [50 80] [70 60] [90 80]
fill "gold"
poly [10 20] [50 50] [20 10] [10 20]
Output
Reference
poly xy:[]num...
The poly
function draws polylines and polygons for the given coordinates. A
polyline is a sequence of connected line segments, and a polygon is a closed polyline.
The poly
function takes a variadic number of arguments of type
[]num
. Each argument has to be a number array with two elements
[x y]
. The first element representing the x coordinate and the second the y
coordinate of a vertex in the polyline or polygon. If the array does not have two
elements, a panic occurs. For example, the poly
function can be called as
follows:
poly [x1 y1] [x2 y2] [x3 y3]
Use fill "none"
to draw a line without filling. To draw a closed
polygon, make sure that the first and last coordinates are the same. The
poly
function does not use or change the cursor position.
#ellipse
ellipse
draws an ellipse for given center, radii and optional tilt, start and
end angles.
Example
// red circle
color "red"
ellipse 50 50 40
// yellow, flat ellipse
color "gold"
ellipse 50 50 40 10
// blue, flat ellipse tilted by 45°
color "blue"
ellipse 50 50 40 10 45
// white, flat, half ellipse tilted by 135°
color "white"
ellipse 50 50 40 10 135 0 180
Output
Reference
ellipse x:num y:num rx:num [ry:num [tilt:num [start:num end:num]]]
The ellipse
function draws an ellipse with the given center, radii, tilt, and
start and end angles. It can take 3, 4, 5, or 7 arguments. Default values are used for
omitted arguments.
The first two arguments are the coordinates of the center of the ellipse. The third argument is the radius of the ellipse in the x direction. The fourth argument is the radius of the ellipse in the y direction. If the fourth argument is omitted, the ellipse is drawn as a circle. The fifth argument is the tilt of the ellipse in degrees, with a default value of 0. The sixth and seventh arguments are the start and end angles of the ellipse in degrees, with default values of 0 and 360, respectively.
#stroke
stroke
sets the color of the outline of shapes.
Example
The following code draws two red squares, one with a blue outline.
width 1
color "red"
rect 30 30
stroke "blue"
rect 30 30
Output
Reference
stroke c:string
The stroke
function sets the color of the stroke to the
given string argument c
. The stroke is the visible line that is drawn when
you use the line function or any other shape function after calling fill "none".
The initial stroke color is "black"
.
#fill
fill
sets the color of the interior of shapes.
Example
The following code draws a red square and a blue square with a red outline.
width 1
color "red"
rect 30 30
fill "blue"
rect 30 30
Output
Reference
fill c:string
The fill
function sets the color of the fill to the given
string argument c
. The fill is the interior of a shape. The initial fill
color is "black"
.
#dash
dash
sets the line dash pattern.
Example
width 2
dash 5 // same as: dash 5 5, dash 5 5 5
hline 85 "red"
dash 10 4 1 4
hline 75 "blue"
dash 10 5 10 // same as: dash 10 5 10 10 5 10
hline 65 "gold"
dash // reset dash
hline 50 "black"
gridn 5 "gray"
func hline y:num c:string
color c
move 0 y
line 100 y
end
Output
Reference
dash segments:num...
The dash
function sets the line dash pattern used when stroking lines. The
dash pattern is specified as a variadic number of arguments, where each argument
represents the length of a dash or gap. For example, the arguments 5 10
would
create a line with 5-unit long dashes and 10-unit long gaps.
If the number of arguments is odd, they are copied and concatenated. For example, the
arguments 10 5 10
would become 10 5 10 10 5 10
. If no arguments
are given, the line returns to being solid.
The initial dash pattern is a solid line.
#linecap
linecap
sets the shape of the ends of lines.
Example
width 5
grid
linecap "round"
hline 70
linecap "butt"
hline 50
linecap "square"
hline 30
func hline y:num
move 10 y
line 90 y
end
Output
Reference
linecap style:string
The linecap
function sets the shape of the ends of lines to the
style
string argument. Valid styles are "round"
,
"butt"
or "square"
. An invalid style takes
no effect.
Style | Description |
---|---|
"round" |
The ends of the line are rounded. |
"butt" |
The ends of the line are squared off at the endpoints. |
"square" |
The ends of the line are squared off by adding a box with an equal width and half the height of the line's thickness. |
The initial linecap style is "round"
.
#text
text
prints text to the canvas at the current cursor position.
Example
move 20 70
text "“Time is an illusion."
move 20 63
text "Lunchtime doubly so.”"
move 35 48
text "― Douglas Adams"
Output
Reference
text s:string
The text
function prints the string argument s
to the canvas at
the current cursor position. The cursor position is not updated after writing text. Only
fill
and color
have an effect on the text;
stroke
has no effect. For more text styling, such as setting
font size or font family, see
font
.
#font
font
sets the font properties for text. The font properties are
family
,size
, weight
, style
,
letterspacing
, baseline
, and align
.
Example
font {family:"Bradley Hand, cursive" size:4}
move 10 65
text "“The wonderful thing about programming"
move 10 60
text "is that anyone can learn it and do it. You"
move 10 55
text "don't have to be a genius or have a specific"
move 10 50
text "background. You just need curiosity and"
move 10 45
text "the willingness to try.”"
// all font properties
font {
size:9
style:"normal" // "normal"
family:"Tahomana, sans-serif" // see https://developer.mozilla.org/en-US/docs/Web/CSS/font-family
weight:900
letterspacing:-0.5 // extra inter-character space. negative allowed. default:0
align:"right" // "left", "right"
baseline:"middle" // "top", "bottom", "alphabetic" (default)
}
move 90 32
color "red"
text "Grace Hopper"
color "black"
font {size:4 letterspacing:0 weight:100 style:"normal"}
move 90 25
text "computer scientist, compiler builder"
Output
The following example shows the effect of the align
and
baseline
properties:
font {size:6 family:"Fira Code, monospace"}
move 25 78
line 25 86
move 25 80
font {align:"left"}
text "left"
move 25 63
line 25 71
move 25 65
font {align:"right"}
text "right"
move 25 48
line 25 56
move 25 50
font {align:"center"}
text "center"
move 55 80
line 90 80
move 55 80
font {baseline:"bottom" align:"left"}
text "bottom"
move 55 65
line 90 65
move 55 65
font {baseline:"top"}
text "top"
move 55 50
line 90 50
move 55 50
font {baseline:"middle"}
text "middle"
move 55 35
line 90 35
move 55 35
font {baseline:"alphabetic"}
text "alphabetic"
Output
Reference
font props:{}any
The font
function sets the font properties for text. The font properties are
family
, size
, weight
, style
,
letterspacing
, align
, and baseline
.
The family
property specifies a prioritized list of one or more font family
names. Values are separated by commas to indicate that they are alternatives. The browser
will select the first available font. For example, the value
"Fira Code, monospace"
would specify that the browser should try to
use the Fira Code font, but if that font is not available, it should use a monospace font.
The default font family is the browser default.
The size
property specifies the height of a letter in canvas units. The
default size is 6.
The weight
property specifies the boldness of the font. The values 100, 200,
..., 900 can be used to specify the weight of the font. The value 400 is normal, 700 is
bold. The default weight is 400.
The style
property specifies the sloping of the font. The values
"normal"
and "italic"
can be used to specify
the style of the font. The default style is "normal".
The letterspacing
property specifies the additional horizontal space between
text characters in canvas units. The default value is 0.
The align
property specifies the horizontal alignment of the text. The values
"left"
, "right"
, and
"center"
can be used to specify the alignment. The default value is
"left"
.
The baseline
property specifies the vertical cursor position relative to the
vertical text position. The values "top"
,
"bottom"
, "middle"
, and
"alphabetic"
can be used to specify the baseline. The default value
is "alphabetic"
.
Here is an example of how to use the font function:
font {
family:"Fira Code, monospace"
size:9
weight:700
style:"italic"
letterspacing:0.5
baseline:"top"
align:"center"
}
This code sets the font properties to use the Fira Code font, a size of 9, a weight of 700, an italic style, a letterspacing of 0.5, a top baseline, and a center alignment.
#Event Handlers
Evy first executes all top-level code in the order it appears in the source code. If there is at least one event handler, Evy then enters an event loop. In the event loop, Evy waits for external events, such as a key press or a pointer down event. When an event occurs, Evy calls the corresponding event handler function if it has been implemented. The event handler function can optionally receive arguments, such as the key character or the pointer coordinates. Once the event handler function has finished, Evy returns to the event loop and waits for the next event.
Event handlers are declared using the on
keyword. Only predefined events can
be handled: key
, down
, up
, move
,
animate
, and input
. For example, the following code defines an
event handler for the key press event:
on key k:string
print k
end
The parameters to the event handlers must match the expected signature. The
key
event handler expects a single parameter of type string, which is the
character that was pressed. The parameters can be fully omitted or fully specified. If
only some parameters are needed, use the anonymous _
parameter. The
down
event handler, for instance, expects two parameters, the x and y
coordinates of the pointer. If you only need the x coordinate, you can use
on down x:num _:num
.
Pointer events, such as down
, up
, and move
, occur
when a pointing input device, such as a mouse, a pen or stylus, or a finger, is used to
interact with the canvas.
#key
key
is called when a key on the keyboard is pressed.
Example
on key k:string
print k
end
Sample output
Escape
Shift
R
o
Reference
key k:string
The key
event handler is called when a keydown event occurs.
The handler is passed a string argument which is the character of the key that was
pressed. For example, if the user presses the a
key, the argument would be
the string "a"
.
Some keys do not have a character representation, such as the arrow keys or the shift key.
For these keys, the argument is a special string, such as
"ArrowRight"
, "ArrowUp"
,
"Shift"
, "Enter"
,
"Control"
, "Alt"
,
"Backspace"
, or "Escape"
.
When the shift key is pressed and then another key is pressed, the argument is the
uppercase or special character representation of the key that was pressed. For example, if
the user presses shift
+a
, the argument is the string
"A"
.
#down
down
is called when the pointer is pressed down.
Example
on down x:num y:num
printf "x: %2.0f y: %2.0f\n" x y
end
Sample output
x: 42 y: 85
x: 7 y: 6
Reference
down x:num y:num
The down
event handler is called when a pointerdown event
occurs on the canvas. The handler is passed two number arguments, x
and
y
, which are the coordinates of the pointer location when the pointer was
pressed down. The pointer is typically a mouse, stylus or finger.
#up
up
is called when the pointer is lifted up.
Example
on up x:num y:num
move x y
color "red"
circle 1
end
Sample output
Reference
up x:num y:num
The up
event handler is called when a pointerup event occurs
on the canvas. The handler is passed two number arguments, x
and
y
, which are the coordinates of the pointer location when the pointer was
lifted up. The pointer is typically a mouse, stylus or finger.
#move
move
is called when the pointer is moved.
Example
The following sample draws a line following the pointer's movement.
down := false
width 1
on down x:num y:num
down = true
move x y
end
on move x:num y:num
if down
line x y
end
end
on up
down = false
end
Sample output
Reference
move x:num y:num
The move
event handler is called when a pointermove event
occurs on the canvas. The handler is passed two number arguments, x
and
y
, which are the coordinates of the position that the pointer has moved to.
The pointer is typically a mouse, stylus or finger.
#animate
animate
gets called periodically around 60 times per second.
Example
semiblack := "hsl(0deg 0% 0% / 10%)"
width 1
fill semiblack
stroke "red"
on animate ms:num
clear semiblack
y := 100 - (ms / 20) % 100
move 50 y
circle 10
end
Output
Reference
animate elapsed:num
The animate
event handler is called when an animation frame is available.
This means that the handler will be called typically 60 times in a second, but it will
generally match the display refresh rate. If the computations within a single animate call
take too long, the frame rate will drop.
The animate event handler is passed a single numeric argument which is the number of elapsed milliseconds since the start of the animation. This allows you to track the progress of the animation and to update the animation accordingly.
#input
input
is called when the value of an input element changes.
Example
on input id:string val:string
print "id:" id "val:" val
end
Sample Output from the Evy website
id: sliderx val: 15
id: slidery val: 0
id: slidery val: 100
Reference
input id:string val:id
The input
event handler is called when the value of an input element changes.
The handler is passed two string arguments: the id of the input element and its new value.
For example, if you have an input element with the id sliderx
and the user
changes the value of the slider to 15
, the input event handler will be called
with the arguments sliderx
and 15
.
The Evy web interface has two sliders that are used as input elements. The sliders range
from 0 to 100, and their ids are sliderx
and slidery
. When you
change the position of the sliders the input
event handler is called with the
new position value of the slider.