Built-in Functions
Risor includes this set of default built-in functions. The set of available built-ins is easily customizable, depending on the goals for your project.
all
all(container) boolReturns true if all objects in the given container are "truthy".
>>> all([true, 1, "ok"])
true
>>> all([true, 0, "ok"])
falseany
any(container) boolReturns true if any of the objects in the given container are "truthy".
>>> any([false, 0, "ok"])
true
>>> any([false, 0, ""])
falseassert
assert(object, message)Generates an error if x is "falsy". If a message is provided, it is used as
the assertion error message.
>>> assert(1 == 1) // no effect
>>> assert(1 == 1, "check failed") // no effect
>>> assert(1 == 2, "check failed") // raises error
check failed
>>> assert(1 == 2) // raises error
assertion failedbool
bool(object) boolReturns true or false depending on whether the object is considered "truthy".
Container types including lists, maps, sets, and strings evaluate to false when
empty and true otherwise.
>>> bool(1)
true
>>> bool(0)
false
>>> bool([1])
true
>>> bool([])
falsebuffer
buffer(object) bufferReturns a Buffer object that wraps a Go bytes.Buffer.
>>> buffer(5)
buffer("\x00\x00\x00\x00\x00")
>>> buffer(byte_slice([65, 66, 67]))
buffer("ABC")
>>> string(buffer(byte_slice([65, 66, 67])))
"ABC"The Buffer type interoperates easily with Strings and ByteSlices. The Buffer
Go type implements io.ReadWriter (opens in a new tab)
which means it can be provided to any Go function that accepts an
io.Reader or io.Writer.
byte_slice
byte_slice(object) byte_sliceCreates a new slice of bytes, which wraps the Go type []byte. If a single
argument is provided, it is used as the initial capacity of the slice. If a
list of values is provided, the slice is initialized with those values.
>>> byte_slice()
byte_slice("")
>>> byte_slice(5)
byte_slice("\x00\x00\x00\x00\x00")
>>> byte_slice([1, 2, 3])
byte_slice("\x01\x02\x03")
>>> byte_slice([65, 66, 67])
byte_slice("ABC")
>>> byte_slice([65]) + byte_slice([66, 67])
byte_slice("ABC")
>>> string(byte_slice([65, 66, 67]))
"ABC"byte
byte(object) byteReturns a Byte object that wraps a Go byte. The Byte type interoperates
seamlessly with Ints and Floats.
>>> byte()
0
>>> byte(3)
3
>>> byte("3")
3
>>> byte(3) == 3
true
>>> byte(3) + 5.5
8.5call
call(function, ...args object) objectCalls the function with given arguments. This is primarily useful in pipe expressions when a function is being passed through the pipe as a variable.
>>> func inc(x) { x + 1 }
>>> call(inc, 99)
100
>>> inc | call(41)
42cat
cat(path string, ...paths string) stringSimilar to the cat command in Unix, this function concatenates the contents
of the given file path(s) and returns the result as a string.
Assuming the following file exists:
alice
blake>>> cat("names.txt")
"alice\nblake\n"cd
cd(string)Changes the current working directory to the given path.
>>> cd("/tmp")
>>> os.getwd()
"/tmp"chan
chan(capacity int = 0) chanCreates a new channel with the given capacity. If unspecified, the capacity
defaults to 0. Channels are used to send and receive Risor objects between
goroutines. The underlying Go equivalent is chan object.Object. This means
any Risor object can be sent and received over a channel. Currently the Risor
select statement does not support channels, however it may in the future.
>>> c := chan(8)
>>> c <- "test"
>>> <-c
"test"New in Risor v1.4.0.
chr
chr(int) stringConverts an Int to the corresponding unicode rune, which is returned as a String.
The ord built-in performs the inverse transformation.
>>> chr(8364)
"€"
>>> chr(97)
"a"chunk
chunk(container, size int) listReturns a list of chunks of the given container, where each chunk is a list of the given size. If the container is not evenly divisible by the size, the last chunk will contain the remaining elements.
>>> chunk([1, 2, 3, 4, 5], 2)
[[1, 2], [3, 4], [5]]
>>> chunk([1, 2, 3, 4, 5], 3)
[[1, 2, 3], [4, 5]]
>>> chunk([1, 2, 3, 4, 5], 4)
[[1, 2, 3, 4], [5]]
>>> chunk([1, 2, 3, 4, 5], 5)
[[1, 2, 3, 4, 5]]close
close(channel)Closes the given channel. This directly corresponds to the Go close function.
If called on an already closed channel, an error is raised.
c := chan()
go func() {
c <- 42
close(c)
}()
for _, v := range c {
print(v)
}coalesce
coalesce(...objects) objectReturns the first non-nil object in the given list of arguments. If no
arguments are provided, or all arguments are nil, the result is nil.
>>> coalesce(nil, 1, 2, 3)
1
>>> coalesce(nil, nil, nil) # returns nil
>>> coalesce() # returns nilcp
cp(src_path string, dst_path string)Copies the contents of the source file to the destination file. If the destination file already exists, it is overwritten.
>>> cp("foo.txt", "bar.txt")decode
decode(object, codec_name string) objectDecodes the given object using the specified codec. The codec_name is a string that may be one of the following values:
base64base32gziphexjsoncsvurlquery
>>> decode("616263", "hex")
byte_slice("abc")
>>> decode("YWJj", "base64")
byte_slice("abc")
>>> decode("a,b,c\n", "csv")
[["a", "b", "c"]]See additional notes about codecs in the encode section below.
delete
delete(map, key string)Deletes the item with the specified key from the map. This operation has no effect if the key is not present in the map.
>>> m := {one: 1, two: 2}
{"one": 1, "two": 2}
>>> delete(m, "one")
{"two": 2}
>>> delete(m, "foo")
{"two": 2}encode
encode(object, codec_name string) objectEncodes the given object using the specified codec. The codec_name is a string that may be one of the following values:
base64base32gziphexjsoncsvurlquery
>>> encode("abc", "hex")
"616263"
>>> encode("abc", "base64")
"YWJj"
>>> encode([["a", "b", "c"]], "csv")
"a,b,c\n"base64, base32, and hex codecs operate on byte slices or types that can be
automatically converted to a byte slice, such as strings. Other codecs may accept
different types.
Additional codecs may be registered by calling the Go function
builtins.RegisterCodec
gzip encoding added in Risor v1.5.0.
error
error(message string)Raises an Error containing the given message. A try call can be used to catch the error and handle it. Otherwise, the call stack unwinds and error stops execution of the program.
>>> error("kaboom")
kaboomfetch
fetch(url string, opts map) http.responseFetches the content of the given URL and returns an http.response object. The
response object provides access to the HTTP status code, headers, and body.
The following options are supported:
| Name | Type | Description |
|---|---|---|
| method | string | The HTTP method to use. |
| headers | map | The headers to send with the request. |
| params | map | The query parameters to send with the request. |
| body | byte_slice or reader | The request body. |
| timeout | int | Request timeout in milliseconds. |
| data | object | Object to marshal as JSON and send in the request body |
>>> r := fetch("https://httpbin.org/get")
>>> r.status_code
200
>>> r.header
{"Connection": ["keep-alive"], "Content-Length": ["14"], "Content-Type": ["text/plain"], "Date": ["Mon, 15 Jan 2024 00:06:56 GMT"], "Server": ["nginx/1.25.1"], "Vary": ["Origin"]}
>>> r.text()
"143.89.131.113"Visit the http.response documentation for more information about the response object and its attributes.
float_slice
float_slice(object) float_sliceCreates a new slice of floating point values, which wraps the Go type []float64.
If a single argument is provided, it is used as the initial capacity of the slice.
If a list of values is provided, the slice is initialized with those values.
>>> float_slice()
float_slice([])
>>> float_slice(5)
float_slice([0 0 0 0 0])
>>> float_slice([1.1, 2.2, 3.3])
float_slice([1.1 2.2 3.3])
>>> float_slice([1.1, 2.2, 3.3])[0]
1.1float
float(object) floatConverts a String or Int object to a Float. An error is generated if the operation fails.
>>> float()
0
>>> float("4.4")
4.4getattr
getattr(object, name string, default_value object) objectReturns the named attribute from the object, or the default value if the attribute does not exist. The returned attribute is always a Risor object, which may be a function. This is similar to getattr (opens in a new tab) in Python.
>>> l := [1,2,3]
[1, 2, 3]
>>> append := getattr(l, "append")
builtin(list.append)
>>> append(4)
[1, 2, 3, 4]
>>> getattr(l, "unknown", "that doesn't exist")
"that doesn't exist"getenv
getenv(name string) stringReturns the value of the environment variable with the given name. If the variable is not set, an empty string is returned.
>>> getenv("HOME")
"/home/username"hash
hash(b byte_slice, algorithm string) byte_sliceHashes the given byte_slice b using the specified algorithm. If not provided, algorithm defaults to "sha256".
>>> hash("abc")
byte_slice("\xbax\x16\xbf\x8f\x01\xcf\xeaAA@\xde]\xae\"#\xb0\x03a\xa3\x96\x17z\x9c\xb4\x10\xffa\xf2\x00\x15\xad")
>>> hash("a", "md5")
byte_slice("\f\xc1u\xb9\xc0\xf1\xb6\xa81Ă™\xe2iw&a")Available algorithms:
md5sha1sha256sha512
int
int(object) intConverts a String or Float to an Int. An error is generated if the operation fails.
>>> int(4.4)
4
>>> int("123")
123is_hashable
is_hashable(object) boolReturns true if the object is hashable, otherwise returns false. A Risor
object is hashable if it implements the object.Hashable interface, which is
defined in this file (opens in a new tab).
Hashable objects may be stored as elements of a Risor set.
>>> is_hashable("abc")
true
>>> is_hashable([1, 2, 3])
falseiter
iter(container) iteratorReturns an iterator for the given container object. This can be used to iterate
through items in a for loop or interacted with more directly. The returned
iterator has next() and entry() methods which are used to move forward and
to retrieve the current entry, respectively.
>>> s := {"a", "b", "c"}
>>> iterator := iter(s)
>>> iterator.next()
"a"
>>> iterator.next()
"b"
>>> iterator.entry()
iter_entry("b", true)
>>> iterator.entry().key
"b"
>>> iterator.entry().value
truejmespath
jmespath(data object, expression string) objectQueries data using the given JMESPath (opens in a new tab) expression. Note the data is provided as the first argument which makes it useful in pipe expressions.
>>> jmespath({"count": 42, "name": "foo"}, "count")
42
>>> [{"name": "a"}, {"name": "b"}] | jmespath("[].name")
["a", "b"]The jmespath built-in is included in the Risor CLI by default. However if
Risor is being used as a library, the jmespath module must be imported
explicitly.
keys
keys(container) listReturns a list of all keys for items in the given map or list container.
>>> m := {one: 1, two: 2}
{"one": 1, "two": 2}
>>> keys(m)
["one", "two"]len
len(container) intReturns the size of the given container. Container types include:
StringListMapSetFloatSliceByteSlice
>>> len("ab") // string length
2
>>> len([1,2,3]) // list length
3
>>> len({foo:"bar"}) // map length
1
>>> len({1,2,3,4}) // set length
4Note that for String types, the length is the number of underlying runes in
the string, not the number of bytes. This is subtly different than taking the
len(s) of a string in Go, which returns the number of bytes. Conceptually,
the approach Risor takes is that a String is a container for
runes (opens in a new tab).
list
list(container) listReturns a new list populated with items from the given container. If a list is provided, a shallow copy of the list is returned. It is also commonly used to convert a set to a list.
>>> s := {"a", "b", "c"}
{"a", "b", "c"}
>>> list(s)
["a", "b", "c"]ls
ls(path string) listLists the contents of the specified directory. If a directory is not provided,
the current working directory is used. The returned list contains one DirEntry
object for each file or directory in the specified directory.
>>> ls()
[dir_entry(name=file1.txt, type=regular), dir_entry(name=logs, type=dir)]
>>> ls("logs")
[dir_entry(name=logs.txt, type=regular)]make
make(object object, capacity int = 0) objectMost Risor programs do not need to use make explicitly, however it can be
useful when you would like to specify the underlying capacity of a container.
This wraps the Go make function.
The object argument must be one of the following:
- a
list,map, orsetobject. - a built-in function, one of:
chan,list,map, orset.
This object is only used to signal which type of object is being created. The
capacity is specified by the capacity argument, which defaults to 0 if not
provided.
>>> make(list, 10)
[] # empty list, with underlying slice of capacity 10
>>> make([], 10)
[] # empty list, with underlying slice of capacity 10New in Risor v1.4.0.
map
map(container) mapReturns a new map which is populated with the items from the given container
if one is provided. This behaves similarly to dict in Python.
>>> map()
{}
>>> map([["k1", 1], ["k2", 2]])
{"k1": 1, "k2": 2}
>>> map({"a", "b", "c"}) // converts a set to a map
{"a": true, "b": true, "c": true}nslookup
nslookup(name string, query_type string = "HOST", resolver_addr string = "")Look up the given domain name using the specified query type (default "HOST") and resolver address (default "" for system default).
>>> nslookup("google.com")
["172.253.115.138", "172.253.115.100", "172.253.115.139", "172.253.115.113", "172.253.115.101", "172.253.115.102", "2607:f8b0:4004:c08::8b", "2607:f8b0:4004:c08::71", "2607:f8b0:4004:c08::8a", "2607:f8b0:4004:c08::65"]ord
ord(string) intConverts a unicode character to the corresponding Int value. The chr built-in
performs the inverse transformation. An error is generated if a multi-rune string is
provided.
>>> ord("€")
8364
>>> ord("a")
97
>>> chr(ord("€"))
"€"print(args ...object)Prints the provided objects to stdout after converting them to their String
representations. Spaces are inserted between each object and a trailing newline
is output. This is a wrapper around fmt.Println.
>>> print(42, "is the answer")
42 is the answerprintf
printf(format string, args ...object)Printf wraps fmt.Printf in order to print the formatted string and arguments
to stdout. In the Risor REPL you will currently not see the printf output
unless the string ends in a newline character.
>>> printf("name: %s age: %d\n", "joe", 32)
name: joe age: 32reversed
reversed(list) listReturns a new list which is a reversed copy of the provided list.
>>> l := ["a", "b", "c"]
["a", "b", "c"]
>>> reversed(l)
["c", "b", "a"]
>>> l
["a", "b", "c"]set
set(container) setReturns a new set containing the items from the given container object.
>>> set("aabbcc")
{"a", "b", "c"}
>>> set([4,4,5])
{4, 5}
>>> set({one:1, two:2})
{"one", "two"}setenv
setenv(name, value string)Sets the value of the environment variable with the given name to the provided value. If the variable does not exist, it is created.
>>> setenv("FOO", "bar")
>>> getenv("FOO")
"bar"sorted
sorted(container) listReturns a sorted list of items from the given container object.
>>> sorted("cba")
["a", "b", "c"]
>>> sorted([10, 3, -5])
[-5, 3, 10]spawn
spawn(function, args ...object) threadSpawns a new goroutine and executes the given function in that goroutine. The function is passed the remaining arguments. Returns a Risor thread object that can be used to wait for the goroutine to finish and retrieve its return value.
>>> func addone(x) { return x + 1 }
>>> t := spawn(addone, 1)
>>> t.wait()
2When using Risor as a library, this level of concurrency is not available
by default. To enable it, pass the risor.WithConcurrency() option when
initializing a Risor VM.
New in Risor v1.4.0.
sprintf
sprintf(format string, args ...object) stringWraps fmt.Sprintf to format the string with the provided arguments. Risor
objects are converted to their corresponding Go types before being passed to
fmt.Sprintf.
>>> sprintf("name: %s age: %d", "fred", 18)
"name: fred age: 18"
>>> sprintf("%v", [1, "a", 3.3])
"[1 a 3.3]"string
string(object) stringReturns a string representation of the given Risor object.
>>> string({one:1, two:2})
"{\"one\": 1, \"two\": 2}"
>>> string(4.4)
"4.4"
>>> string([1,2,3])
"[1, 2, 3]"try
try(args ...object) objectAccepts one or more functions which are executed in order until one of them
doesn't raise an error and returns that functions return value. If any
non-callable object is reached in the provided arguments, that object is
returned immediately. Otherwise, if all functions raise errors, nil is returned.
>>> func kaboom() { error("kaboom!") }
>>> try(kaboom) // returns nil
>>> try(kaboom, func() { error("this failed too") }) // returns nil
>>> try(kaboom, "fallback") // returns "fallback"
"fallback"
>>> try(42)
42
>>> try(func() { 42 })
42If any function after the first accepts an argument, any error raised by the previous function is passed to the next function as its first argument.
The example below prints caught error: kaboom and then returns the value 33.
try(func() {
error("kaboom")
}, func(err) {
print("caught error:", err)
return 33
})type
type(object) stringReturns the type name of the given object as a String.
>>> type(1)
"int"
>>> type(2.2)
"float"
>>> type("hi")
"string"
>>> type([])
"list"
>>> type({})
"map"
>>> type({1,2,3})
"set"unsetenv
unsetenv(name string)Removes the environment variable with the given name.
>>> setenv("FOO", "bar")
>>> getenv("FOO")
"bar"
>>> unsetenv("FOO")
>>> getenv("FOO")
""