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 askeys.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)—trueif the object contains that key, otherwisefalse.
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:
| Form | Example | Behavior |
|---|---|---|
| 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:
- Merges the imported file's globals into the root (current) global scope, so you can call its functions directly by name.
- 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]).
Errors raised by builtins surface as script errors with a status code and a message. See Error Handling.