Skip to main content

Built-in Functions

All builtins are restricted — scripts may call them but never reassign or modify them. Call help() to list them from inside a script.

Output and inspection

print(value, ...) — prints values to stdout separated by spaces, followed by a newline. Returns nil.

info(value) — returns a string containing the value's type and description info.

type(value) — returns the type name as a string.

len(value) — returns the size of an array, object, or string.

print("count", 42) // count 42
print(type(42)) // int
print(len("abc")) // 3
print(info([1, 2, 3])) // type + description info

keys, values, has, items

Introspect an object's contents:

  • keys(obj) — an array of the object's key names (an object is required; passing an array errors).
  • values(obj) — an array of the object's values, in the same order as keys.
  • items(obj) — an array of {key, value} objects, one per member — handy when you need both the key and its value together.
  • has(obj, key)true if the object contains that key, otherwise false.
var user = {name: "Ada", age: 36, admin: false}

print(keys(user)) // e.g. ["admin", "name", "age"] (any order)
print(values(user)) // e.g. [false, "Ada", 36] (same order as keys)
print(has(user, "name")) // true
print(has(user, "email")) // false
print(len(user)) // 3

var entries = items(user) // array of {key, value} objects
print(entries[0].key) // e.g. "age"
print(entries[0].value) // e.g. 36

for (entry : items(user)) {
print(entry.key, "=", entry.value) // walk every member in one loop
}

Key order is not guaranteed — the engine stores object members in an unordered structure, so keys() and values() may come back in any order (here they happen to line up positionally, so values()[i] corresponds to keys()[i] only within a single call and is not safe to rely on across runs). To check a key safely regardless of order, use has().

The classic "look up by key" pattern is has + index:

var settings = {theme: "dark", volume: 80}
if (has(settings, "theme")) {
print(settings["theme"]) // dark
}

keys / values / has are restricted globals, like all builtins — you can call them but never reassign them.

Conversion

to_string(value) // any value -> string
int(value) // -> int
long(value) // -> long
float(value) // -> float
double(value) // -> double
var i = int("42")
var l = long("3000000000")
var f = float("3.14")
var d = double("2.718")
var s = to_string(42)

Values

version() — returns an array ["Scrii", <version>, <build date>].

var v = version()
print("Engine:", v[0], v[1], "built", v[2])

insert and erase

insert adds items to an array or object; erase removes items from an array or object (or an entire variable). Both accept a single selector (one index or key) or an array of selectors (several indices or keys at once).

Two distinct ways to use them:

FormExampleBehavior
Builtin (bare name)a = erase(a, 1)Pure — returns the modified copy, does not change the argument
Pipe (colon)a:erase(1)In place — reassigns the receiver

Arrays and objects have value semantics, so the builtin returns a new value that you must assign. The pipe form is the idiomatic in-place operator.

erase

Arrays — by index, or by an array of indices:

var a = [10, 20, 30, 40, 50]
erase(a, 1) // pure: does NOT change a
print(a) // [10, 20, 30, 40, 50]
a = erase(a, 1) // assign the result
print(a) // [10, 30, 40, 50]

var b = [10, 20, 30, 40, 50]
b = erase(b, [1, 3]) // remove indices 1 and 3
print(b) // [10, 30, 50]

Objects — by key, or by an array of keys:

var o = {a: 1, b: 2, c: 3, d: 4}
o = erase(o, "b") // remove one key
print(o) // {a: 1, c: 3, d: 4}

var o2 = {a: 1, b: 2, c: 3}
o2 = erase(o2, ["a", "c"]) // remove several keys
print(o2) // {b: 2}

Variables:

erase(some_global) // remove a top-level variable entirely

In place with the pipe operator:

var a = [10, 20, 30, 40, 50]
a:erase(1) // a -> [10, 30, 40, 50]
a:erase([1, 3]) // a -> [10, 50]

var o = {a: 1, b: 2, c: 3}
o:erase("b") // o -> {a: 1, c: 3}
o:erase(["a", "c"]) // o -> {b: 2}

The selector array works the same whether it is written inline (erase(a, [1, 3])) or passed as a variable:

var drop = [0, 2]
var nums = [7, 8, 9, 10]
nums = erase(nums, drop) // [8, 10]
var gone = ["temp"]
var obj = {temp: 1, keep: 2}
obj = erase(obj, gone) // {keep: 2}

insert

Arrays — a single item (optionally at an index):

var a = [1, 3]
a = insert(a, 2, 1) // insert 2 at index 1 -> [1, 2, 3]
var b = [1, 2]
b = insert(b, 4) // append (index defaults to the end) -> [1, 2, 4]

Arrays — splice an array of items (optionally at an index):

var c = [1, 4]
c = insert(c, [2, 3], 1) // splice [2, 3] in at index 1 -> [1, 2, 3, 4]
var d = [1, 2]
d = insert(d, [3, 4]) // append the array -> [1, 2, 3, 4]

Objects — merge another object's keys:

var x = {a: 1}
x = insert(x, {b: 2}) // merge -> {a: 1, b: 2}

In place with the pipe operator:

var a = [1, 3]
a:insert(2, 1) // a -> [1, 2, 3]
a:insert([4, 5]) // a -> [1, 2, 3, 4, 5]

var o = {a: 1, b: 2}
o:insert({c: 3}) // o -> {a: 1, b: 2, c: 3}

When you insert an array without an index it is spliced (its elements are appended), not added as a single nested element:

var e = [1, 2]
e = insert(e, [3, 4]) // [1, 2, 3, 4] (spliced, not [1, 2, [3, 4]])

import

import(file) — loads and executes another .scr file (extension optional). It does two things:

  1. Merges the imported file's globals into the root (current) global scope, so you can call its functions directly by name.
  2. Returns an object holding the imported globals, so you can also reach them namespaced through the return value (and tell them apart from any colliding names).
var math = import("libs/helper")
print(math.factorial(5)) // via the returned object
print(factorial(5)) // via the merged root global — same value

Every var/fn at the top level of the imported file is exported: the import's namespace object has one key per global, and that same name is bound directly in the importing script's root scope.

// libs/helper.scr
fn factorial(n) {
if (n <= 1) { return 1 }
return n * factorial(n - 1)
}
var helper_name = "helper"
// main.scr
var h = import("libs/helper")
print(h.factorial(6)) // 720 (via object)
print(factorial(6)) // 720 (via root scope)
print(helper_name) // helper (imported global is available too)
print(keys(h)) // ["factorial", "helper_name"]

Importing is not scoped to the block where import appears — the globals always land in the root scope. Beware collisions: an imported name that overlaps an existing restricted global (such as a builtin like double or an already-imported name) raises a REASSIGN_RESTRICTED error.

Imports resolve relative to the importing file (or via engine-configured search paths).

load_plugin / unload_plugin

load_plugin("./myplugin.so") // true on success
print(shout("hi")) // registers restricted globals

unload_plugin("./myplugin.so") // removes its globals

pipe / pipe_remove

pipe(name, fn) registers name in the pipe table so receiver:name(args) calls fn(receiver, args); pipe_remove(name) unregisters it. See Pipes for the full story.

pipe("double", fn(n) { return n * 2 })
var x = 21
x:double() // x -> 42
print(pipe_remove("double")) // true

help

help() — returns a string listing the core builtins as name - description, so you can see what's available without guessing. Note the listing is captured at registration time, so load_plugin / unload_plugin and the std module are not part of it — use help(std) to browse those.

help(obj) — for an object or module, returns a string with the object's own description followed by one name - description line for each member. Because every member carries a description line, you can see exactly what is at that layer and never have to guess at its contents.

print(help()) // core builtins, one per line
print(help(std)) // every module + the OS basics on std
print(help(std.string)) // the string functions, one per line

The descriptions describe each member, so you can drill into the next layer: help() on a module shows its function names and purposes, and you can then call help() on any nested member to keep descending:

print(help(std)) // ... string - String Manipulation, ...
print(help(std.string)) // ... upper - upper(s) - Converts string to uppercase, ...
var mods = [std.string, std.math]
print(help(mods[0])) // same as help(std.string) — help also takes array elements

help(value) on any other value returns just that value's own description (empty for scalars and arrays unless they carry one via the -> describe operator). Arrays are not listed element-by-element — to inspect an array, pass each element, e.g. help(arr[i]).

note

Errors raised by builtins surface as script errors with a status code and a message. See Error Handling.