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)—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.
values()[i] lines up with keys()[i] only by accident of a single
iteration, never as a contract: iterate with items() (or for (k, v : obj))
whenever key and value must stay paired.
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)
All five are also pipes that rewrite the receiver in place (see
Pipes):
var flt = 1.04
flt:int() # flt -> 1
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
erase("other_global") # same thing, with the name as a string
With one argument, erase deletes a top-level variable, not a value:
the argument is evaluated and its string value is used as the variable
name (erase(some_global) works when some_global holds a string; a
non-string argument is an error). Erasing a restricted name (like std or
a builtin) is refused.
Erasing a name shared through ref aliases tombstones the shared storage:
every alias reads nil afterwards instead of orphaned data — whether the
erased name was the original or one of the aliases (see
Sharing nested storage with ref):
var a = 4
ref b = a
erase("a")
print(b) # nil
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 — see Import
for the full story (namespace merging, exports, search paths, collisions).
load_plugin / unload_plugin
Native plugins are covered on their own page: Native Plugins.
In short, load_plugin("./myplugin.so") registers restricted globals and
unload_plugin("./myplugin.so") removes them again.
pipe / pipe_remove
Pipes live on their own page: Pipes. In short,
pipe("twice", fn(n) { return n * 2 }) registers receiver:twice(args) and
pipe_remove("twice") unregisters it.
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.