• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/ucode/README.md

  1 # ABOUT
  2 
  3 The ucode language is a tiny general purpose scripting language featuring a
  4 syntax closely resembling ECMAScript. It can be used in a stand-alone manner
  5 by using the ucode command line interpreter or embedded into host applications
  6 by linking libucode and utilizing its C language API. Additionally, ucode can
  7 be invoked in template mode where control flow and expression logic statements
  8 are embedded in Jinja-like markup blocks.
  9 
 10 Besides aiming for small size, the major design goals of ucode are the ability
 11 to trivially read and write JSON data, good embeddability into C applications,
 12 template capabilities for output formatting, extensiblity through loadable
 13 native extension modules and a straightforward set of built-in functions
 14 mimicking those found in the Perl 5 language.
 15 
 16 ## HISTORY AND MOTIVATION
 17 
 18 In spring 2021 it has been decided to rewrite the OpenWrt firewall framework on
 19 top of nftables with the goal to replace the then current C application with a
 20 kind of preprocessor generating nftables rulesets using a set of templates
 21 instead of relying on built-in hardcoded rules like its predecessor.
 22 
 23 That decision spurred the development of *ucode*, initially meant to be a
 24 simple template processor solely for the OpenWrt nftables firewall but quickly
 25 evolving into a general purpose scripting language suitable for a wider range
 26 of system scripting tasks.
 27 
 28 Despite OpenWrt predominantly relying on POSIX shell and Lua as system
 29 scripting languages already, a new solution was needed to accomodate the needs
 30 of the new firewall implementation; mainly the ability to efficiently deal with
 31 JSON data and complex data structures such as arrays and dictionaries and the
 32 ability to closely interface with OpenWrt's *ubus* message bus system.
 33 
 34 Throughout the design process of the new firewall and its template processor,
 35 the following design goals were defined for the *ucode* scripting language:
 36 
 37  - Ability to embed code logic fragments such as control flow statements,
 38    function calls or arithmetic expressions into plain text templates, using
 39    a block syntax and functionality roughly inspired by Jinja templates
 40  - Built-in support for JSON data parsing and serialization, without the need
 41    for external libraries
 42  - Distinct array and object types (compared to Lua's single table datatype)
 43  - Distinct integer and float types and guaranteed 64bit integer range
 44  - Built-in support for bit operations
 45  - Built-in support for (POSIX) regular expressions
 46  - A comprehensive set of built-in standard functions, inspired by the core
 47    functions found in the Perl 5 interpreter
 48  - Staying as close to ECMAScript syntax as possible due to higher developer
 49    familiarity and to be able to reuse existing tooling such as editor syntax
 50    highlighting
 51  - Bindings for all relevant Linux and OpenWrt APIs, such as *ubus*, *uci*,
 52    *uloop*, *netlink* etc.
 53  - Procedural, synchronous programming flow
 54  - Very small executable size (the interpreter and runtime is currently around
 55    64KB on ARM Cortex A9)
 56  - Embeddability into C host applications
 57 
 58 Summarized, *ucode* can be described as synchronous ECMAScript without the
 59 object oriented standard library.
 60 
 61 
 62 # INSTALLATION
 63 
 64 ## OpenWrt
 65 
 66 In OpenWrt 22.03 and later, *ucode* should already be preinstalled. If not,
 67 it can be installed via the package manager, using the `opkg install ucode`
 68 command.
 69 
 70 ## MacOS
 71 
 72 To build on MacOS, first install *cmake* and *json-c* via
 73 [Homebrew](https://brew.sh/), then clone the ucode repository and execute
 74 *cmake* followed by *make*:
 75 
 76     $ brew install cmake json-c
 77     $ git clone https://github.com/jow-/ucode.git
 78     $ cd ucode/
 79     $ cmake -DUBUS_SUPPORT=OFF -DUCI_SUPPORT=OFF -DULOOP_SUPPORT=OFF .
 80     $ make
 81     $ sudo make install
 82 
 83 ## Debian
 84 
 85 The ucode repository contains build recipes for Debian packages, to build .deb
 86 packages for local installation, first install required development packages,
 87 then clone the repository and invoke *dpkg-buildpackage* to produce the binary
 88 package files:
 89 
 90     $ sudo apt-get install build-essential devscripts debhelper libjson-c-dev cmake
 91     $ git clone https://github.com/jow-/ucode.git
 92     $ cd ucode/
 93     $ dpkg-buildpackage -b -us -uc
 94     $ sudo dpkg -i ../ucode*.deb ../libucode*.deb
 95 
 96 ## Other Linux systems
 97 
 98 To install ucode from source on other systems, ensure that the json-c library
 99 and associated development headers are installed, then clone and compile the
100 ucode repository:
101 
102     $ git clone https://github.com/jow-/ucode.git
103     $ cd ucode/
104     $ cmake -DUBUS_SUPPORT=OFF -DUCI_SUPPORT=OFF -DULOOP_SUPPORT=OFF .
105     $ make
106     $ sudo make install
107 
108 
109 # SYNTAX
110 
111 ## Template mode
112 
113 By default, *ucode* is executed in *raw mode*, means it expects a given source
114 file to only contain script code. By invoking the ucode interpreter with the
115 `-T` flag or by using the `utpl` alias, the *ucode* interpreter is switched
116 into *template mode* where the source file is expected to be a plaintext file
117 containing *template blocks* containing ucode script expressions or comments.
118 
119 ### Block types
120 
121 There are three kinds of blocks; *expression blocks*, *statement blocks* and
122 *comment blocks*. The former two embed code logic using ucode's JavaScript-like
123 syntax while the latter comment block type is simply discarded during
124 processing.
125 
126 
127 #### 1. Statement block
128 
129 Statement blocks are enclosed in an opening `{%` and a closing `%}` tag and
130 may contain any number of script code statements, even entire programs.
131 
132 It is allowed to omit the closing `%}` of a statement block to parse the
133 entire remaining source text after the opening tag as ucode script.
134 
135 By default, statement blocks produce no output and the entire block is
136 reduced to an empty string during template evaluation but contained script
137 code might invoke functions such as `print()` to explicitly output contents.
138 
139 For example the following template would result in `The epoch is odd` or
140 `The epoch is even`, depending on the current epoch value:
141 
142 `The epoch is {% if (time() % 2): %}odd{% else %}even{% endif %}!`
143 
144 
145 #### 2. Expression block
146 
147 Expression blocks are enclosed in an opening `{{` and a closing `}}` tag and
148 may only contain a single expression statement (multiple expressions may be
149 chained with comma). The implicit result of the rightmost evaluated expression
150 is used as output when processing the block.
151 
152 For example the template `Hello world, {{ getenv("USER") }}!` would result in
153 the output "Hello world, user!" where `user` would correspond to the name of
154 the current user executing the ucode interpreter.
155 
156 
157 #### 3. Comment block
158 
159 Comment blocks, which are denoted with an opening `{#` and a closing `#}` tag
160 may contain arbitrary text except the closing `#}` tag itself. Comments blocks
161 are completely stripped during processing and are replaced with an empty string.
162 
163 The following example template would result in the output "Hello world":
164 
165 `Hello {# mad #}word`
166 
167 
168 ### Whitespace handling
169 
170 Each block start tag may be suffixed with a dash to strip any whitespace
171 before the block and likewise any block end tag may be prefixed with a dash
172 to strip any whitespace following the block.
173 
174 Without using whitespace stripping, the following example:
175 
176 ```
177 This is a first line
178 {% for (x in [1, 2, 3]): %}
179 This is item {{ x }}.
180 {% endfor %}
181 This is the last line
182 ```
183 
184 Would result in the following output:
185 
186 ```
187 This is a first line
188 
189 This is item 1.
190 This is item 2.
191 This is item 3.
192 
193 This is the last line
194 ```
195 
196 By adding a trailing dash to apply whitespace stripping after the block, the
197 empty lines can be eliminated:
198 
199 ```
200 This is a first line
201 {% for (x in [1, 2, 3]): -%}
202 This is item {{ x }}.
203 {% endfor -%}
204 This is the last line
205 ```
206 
207 Output:
208 
209 ```
210 This is a first line
211 This is item 1.
212 This is item 2.
213 This is item 3.
214 This is the last line
215 ```
216 
217 By applying whitespace stripping before the block, all lines can be joined
218 into a single output line:
219 
220 ```
221 This is a first line
222 {%- for (x in [1, 2, 3]): -%}
223 This is item {{ x }}.
224 {%- endfor -%}
225 This is the last line
226 ```
227 
228 Output:
229 
230 ```
231 This is a first lineThis is item 1.This is item 2.This is item 3.This is the last line
232 ```
233 
234 ## Script syntax
235 
236 The ucode script language - used either within statement and expression blocks
237 or throughout the entire file in *raw mode*, uses untyped variables and employs
238 a simplified JavaScript like syntax.
239 
240 The language implements function scoping and differentiates between local and
241 global variables. Each function has its own private scope while executing and
242 local variables declared inside a function are not accessible in the outer
243 calling scope.
244 
245 ### 1. Data types
246 
247 Ucode supports seven different basic types as well as two additional special
248 types; function values and ressource values. The supported types are:
249 
250  - Boolean values (`true` or `false`)
251  - Integer values (`-9223372036854775808` to `+9223372036854775807`)
252  - Double values (`-1.7e308` to `+1.7e308`)
253  - String values (e.g. `'Hello world!'` or `"Sunshine \u2600!"`)
254  - Array values (e.g. `[1, false, "foo"]`)
255  - Object values (e.g. `{ foo: true, "bar": 123 }`)
256  - Null value (`null`)
257 
258 Ucode utilizes reference counting to manage memory used for variables and values
259 and frees data automatically as soon as values go out of scope.
260 
261 Numeric values are either stored as signed 64bit integers or as IEEE 756 double
262 value. Conversion between integer and double values can happen implicitly, e.g.
263 through numeric operations, or explicitely, e.g. by invoking functions such as
264 `int()`.
265 
266 ### 2. Variables
267 
268 Variable names must start with a letter or an underscore and may only contain
269 the characters `A`..`Z`, `a`..`z`, `0`..`9` or `_`. By prefixing a variable
270 name with the keyword `let`, it is declared in the local block scope only
271 and not visible outside anymore.
272 
273 Variables may also be declared using the `const` keyword. Such variables follow
274 the same scoping rules as `let` declared ones but they cannot be modified after
275 they have been declared. Any attempt to do so will result in a syntax error
276 during compilation.
277 
278 ```javascript
279 {%
280 
281   a = 1;  // global variable assignment
282 
283   function test() {
284     let b = 2;  // declare `b` as local variable
285     a = 2;        // overwrite global a
286   }
287 
288   test();
289 
290   print(a, "\n");  // outputs "2"
291   print(b, "\n");  // outputs nothing
292 
293   const c = 3;
294   print(c, "\n");  // outputs "3"
295 
296   c = 4;           // raises syntax error
297   c++;             // raises syntax error
298 
299   const d;         // raises syntax error, const variables must
300                    // be initialized at declaration time
301 
302 %}
303 ```
304 
305 ### 3. Control statements
306 
307 Similar to JavaScript, ucode supports `if`, `for` and `while` statements to
308 control execution flow.
309 
310 #### 3.1. Conditional statement
311 
312 If/else blocks can be used to execute statements depending on a condition.
313 
314 ```javascript
315 {%
316 
317   user = getenv("USER");
318 
319   if (user == "alice") {
320       print("Hello Alice!\n");
321   }
322   else if (user == "bob") {
323       print("Hello Bob!\n");
324   }
325   else {
326       print("Hello guest!\n");
327   }
328 
329 %}
330 ```
331 
332 If only a single statement is wrapped by an if or else branch, the enclosing
333 curly braces may be omitted:
334 
335 ```javascript
336 {%
337 
338   if (rand() == 3)
339       print("This is quite unlikely\n");
340 
341 %}
342 ```
343 
344 #### 3.2. Loop statements
345 
346 Ucode script supports three different flavors of loop control statements; a
347 `while` loop that executes enclosed statements as long as the loop condition is
348 fulfilled, a `for in` loop that iterates keys of objects or items of arrays and
349 a counting `for` loop that is a variation of the `while` loop.
350 
351 ```javascript
352 {%
353 
354   i = 0;
355   arr = [1, 2, 3];
356   obj = { Alice: 32, Bob: 54 };
357 
358   // execute as long as condition is true
359   while (i < length(arr)) {
360       print(arr[i], "\n");
361       i++;
362   }
363 
364   // execute for each item in arr
365   for (n in arr) {
366       print(n, "\n");
367   }
368 
369   // execute for each key in obj
370   for (person in obj) {
371       print(person, " is ", obj[person], " years old.\n");
372   }
373 
374   // execute initialization statement (j = 0) once
375   // execute as long as condition (j < length(arr)) is true
376   // execute step statement (j++) after each iteration
377   for (j = 0; j < length(arr); j++) {
378       print(arr[j], "\n");
379   }
380 
381 %}
382 ```
383 
384 #### 3.3. Alternative syntax
385 
386 Since conditional statements and loops are often used for template formatting
387 purposes, e.g. to repeat a specific markup for each item of a list, ucode
388 supports an alternative syntax that does not require curly braces to group
389 statements but that uses explicit end keywords to denote the end of the control
390 statement body for better readability instead.
391 
392 The following two examples first illustrate the normal syntax, followed by the
393 alternative syntax that is more suitable for statement blocks:
394 
395 ```
396 Printing a list:
397 {% for (n in [1, 2, 3]) { -%}
398   - Item #{{ n }}
399 {% } %}
400 ```
401 
402 The alternative syntax replaces the opening curly brace (`{`) with a colon
403 (`:`) and the closing curly brace (`}`) with an explicit `endfor` keyword:
404 
405 ```
406 Printing a list:
407 {% for (n in [1, 2, 3]): -%}
408   - Item #{{ n }}
409 {% endfor %}
410 ```
411 
412 For each control statement type, a corresponding alternative end keyword is defined:
413 
414   - `if (...): ... endif`
415   - `for (...): ... endfor`
416   - `while (...): ... endwhile`
417 
418 
419 ### 4. Functions
420 
421 Ucode scripts may define functions to group repeating operations into reusable
422 operations. Functions can be both declared with a name, in which case they're
423 automatically registered in the current scope, or anonymously which allows
424 assigning the resulting value to a variable, e.g. to build arrays or objects of
425 functions:
426 
427 ```javascript
428 {%
429 
430   function duplicate(n) {
431        return n * 2;
432   }
433 
434   let utilities = {
435       concat: function(a, b) {
436           return "" + a + b;
437       },
438       greeting: function() {
439           return "Hello, " + getenv("USER") + "!";
440       }
441   };
442 
443 -%}
444 
445 The duplicate of 2 is {{ duplicate(2) }}.
446 The concatenation of 'abc' and 123 is {{ utilities.concat("abc", 123) }}.
447 Your personal greeting is: {{ utilities.greeting() }}.
448 ```
449 
450 #### 4.1. Alternative syntax
451 
452 Function declarations support the same kind of alternative syntax as defined
453 for control statements (3.3.)
454 
455 The alternative syntax replaces the opening curly brace (`{`) with a colon
456 (`:`) and the closing curly brace (`}`) with an explicit `endfunction`
457 keyword:
458 
459 ```
460 {% function printgreeting(name): -%}
461   Hallo {{ name }}, nice to meet you.
462 {% endfunction -%}
463 
464 <h1>{{ printgreeting("Alice") }}</h1>
465 ```
466 
467 
468 ### 5. Operators
469 
470 Similar to JavaScript and C, ucode scripts support a range of different
471 operators to manipulate values and variables.
472 
473 #### 5.1. Arithmetic operations
474 
475 The operators `+`, `-`, `*`, `/`, `%`, `++` and `--` allow to perform
476 additions, substractions, multiplications, divisions, modulo, increment or
477 decrement operations respectively where the result depends on the type of
478 involved values.
479 
480 The `++` and `--` operators are unary, means that they only apply to one
481 operand. The `+` and `-` operators may be used in unary context to either
482 convert a given value to a numeric value or to negate a given value.
483 
484 If either operand of the `+` operator is a string, the other one is converted
485 to a string value as well and a concatenated string is returned.
486 
487 All other arithmetic operators coerce their operands into numeric values.
488 Fractional values are converted to doubles, other numeric values to integers.
489 
490 If either operand is a double, the other one is converted to a double value as
491 well and a double result is returned.
492 
493 Divisions by zero result in the special double value `Infinity`. If an operand
494 cannot be converted to a numeric value, the result of the operation is the
495 special double value `NaN`.
496 
497 ```javascript
498 {%
499   a = 2;
500   b = 5.2;
501   s1 = "125";
502   s2 = "Hello world";
503 
504   print(+s1);      // 125
505   print(+s2);      // NaN
506   print(-s1);      // -125
507   print(-s2);      // NaN
508   print(-a);       // -2
509 
510   print(a++);      // 2 (Return value of a, then increment by 1)
511   print(++a);      // 4 (Increment by 1, then return value of a)
512 
513   print(b--);      // 5.2 (Return value of b, then decrement by 1)
514   print(--b);      // 3.2 (Decrement by 1, then return value of b)
515 
516   print(4 + 8);    // 12
517   print(7 - 4);    // 3
518   print(3 * 3);    // 9
519 
520   print(10 / 4);   // 2 (Integer division)
521   print(10 / 4.0); // 2.5 (Double division)
522   print(10 / 0);   // Infinity
523 
524   print(10 % 7);   // 3
525   print(10 % 7.0); // NaN (Modulo is undefined for non-integers)
526 %}
527 ```
528 
529 #### 5.2. Bitwise operations
530 
531 The operators `&`, `|`, `^`, `<<`, `>>` and `~` allow to perform bitwise and,
532 or, xor, left shift, right shift and complement operations respectively.
533 
534 The `~` operator is unary, means that is only applies to one operand.
535 
536 ```javascript
537 {%
538   print(0 & 0, 0 & 1, 1 & 1);  // 001
539   print(0 | 0, 0 | 1, 1 | 1);  // 011
540   print(0 ^ 0, 0 ^ 1, 1 ^ 1);  // 010
541   print(10 << 2);              // 40
542   print(10 >> 2);              // 2
543   print(~15);                  // -16 (0xFFFFFFFFFFFFFFF0)
544 %}
545 ```
546 
547 An important property of bitwise operators is that they're coercing their
548 operand values to whole integers:
549 
550 ```javascript
551 {%
552   print(12.34 >> 0);   // 12
553   print(~(~12.34));    // 12
554 %}
555 ```
556 
557 #### 5.3. Relational operations
558 
559 The operators `==`, `!=`, `<`, `<=`, `>` and `>=` test whether their operands
560 are equal, inequal, lower than, lower than/equal to, higher than or higher
561 than/equal to each other respectively.
562 
563 If both operands are strings, their respective byte values are compared, if
564 both are objects or arrays, their underlying memory addresses are compared.
565 
566 In all other cases, both operands are coerced into numeric values and the
567 resulting values are compared with each other.
568 
569 This means that comparing values of different types will coerce them both to
570 numbers.
571 
572 The result of the relational operation is a boolean indicating truishness.
573 
574 ```javascript
575 {%
576   print(123 == 123);     // true
577   print(123 == "123");   // true!
578   print(123 < 456);      // true
579   print(123 > 456);      // false
580   print(123 != 456);     // true
581   print(123 != "123");   // false!
582   print({} == {});       // false (two different anonymous objects)
583   a = {}; print(a == a); // true (same object)
584 %}
585 ```
586 
587 #### 5.4. Logical operations
588 
589 The operators `&&`, `||`, `??` and `!` test whether their operands are all true,
590 partially true, null or false respectively.
591 
592 In the case of `&&` the rightmost value is returned while `||` results in the
593 first truish and `??` in the first non-null value.
594 
595 The unary `!` operator will result in `true` if the operand is not trueish,
596 otherwise it will result in `false`.
597 
598 Operands are evaluated from left to right while testing truishness, which means
599 that expressions with side effects, such as function calls, are only executed
600 if the preceeding condition was satisifed.
601 
602 ```javascript
603 {%
604   print(1 && 2 && 3);                 // 3
605   print(1 || 2 || 3);                 // 1
606   print(2 > 1 && 3 < 4);              // true
607   print(doesnotexist ?? null ?? 42);  // 42
608   print(1 ?? 2 ?? 3);                 // 1
609   print(!false);                      // true
610   print(!true);                       // false
611 
612   res = test1() && test2();  // test2() is only called if test1() returns true
613 %}
614 ```
615 
616 #### 5.5. Assignment operations
617 
618 In addition to the basic assignment operator `=`, most other operators have a
619 corresponding shortcut assignment operator which reads the specified variable,
620 applies the operation and operand to it, and writes it back.
621 
622 The result of assignment expressions is the assigned value.
623 
624 ```javascript
625 {%
626   a = 1;     // assign 1 to variable a
627   a += 2;    // a = a + 2;
628   a -= 3;    // a = a - 3;
629   a *= 4;    // a = a * 4;
630   a /= 5;    // a = a / 5;
631   a %= 6;    // a = a % 6;
632   a &= 7;    // a = a & 7;
633   a |= 8;    // a = a | 8;
634   a ^= 9;    // a = a ^ 9;
635   a <<= 10;  // a = a << 10;
636   a >>= 11;  // a = a >> 11;
637   a &&= 12;  // a = a && 12;
638   a ||= 13;  // a = a || 13;
639   a ??= 14;  // a = a ?? 14;
640 
641   print(a = 2);  // 2
642 %}
643 ```
644 
645 #### 5.6. Miscellaneous operators
646 
647 Besides the operators described so far, ucode script also supports a `delete`
648 operator which removes a property from an object value.
649 
650 ```javascript
651 {%
652   a = { test: true };
653 
654   delete a.test;         // true
655   delete a.notexisting;  // false
656 
657   print(a);              // { }
658 %}
659 ```
660 
661 ### 6. Functions
662 
663 Ucode scripts may call a number of built-in functions to manipulate values or
664 to output information.
665 
666 #### 6.1. `abs(x)`
667 
668 Returns the absolute value of the given operand. Results in `NaN` if operand is
669 not convertible to number.
670 
671 ```javascript
672 abs(1);        // 1
673 abs(-2);       // 2
674 abs(-3.5);     // 3.5
675 abs("0x123");  // 291
676 abs("-0x123"); // NaN
677 abs([]);       // NaN
678 ```
679 
680 #### 6.2. `atan2(x, y)`
681 
682 Calculates the principal value of the arc tangent of x/y, using the signs of
683 the two arguments to determine the quadrant of the result.
684 
685 #### 6.3. `chr(n1, ...)`
686 
687 Converts each given numeric value to a byte and return the resulting string.
688 Invalid numeric values or values < 0 result in `\0` bytes, values larger than
689 255 are truncated to 255.
690 
691 ```javascript
692 chr(65, 98, 99);  // "Abc"
693 chr(-1, 300);     // string consisting of an `0x0` and a `0xff` byte
694 ```
695 
696 #### 6.4. `cos(x)`
697 
698 Return the cosine of x, where x is given in radians.
699 
700 #### 6.5. `die(msg)`
701 
702 Raise an exception with the given message and abort execution.
703 
704 #### 6.6. `exists(obj, key)`
705 
706 Return `true` if the given key is present within the object passed as first
707 argument, otherwise `false`.
708 
709 #### 6.7. `exit(n)`
710 
711 Terminate the interpreter with the given exit code.
712 
713 #### 6.8. `exp(n)`
714 
715 Return the value of e (the base of natural logarithms) raised to the power
716 of n.
717 
718 #### 6.9. `filter(arr, fn)`
719 
720 Filter the array passed as first argument by invoking the function specified
721 in the second argument for each array item.
722 
723 If the invoked function returns a truish result, the item is retained,
724 otherwise it is dropped. The filter function is invoked with three arguments:
725 
726  1. The array value
727  2. The current index
728  3. The array being filtered
729 
730 Returns the filtered array.
731 
732 ```javascript
733 // filter out any empty string:
734 a = filter(["foo", "", "bar", "", "baz"], length)
735 // a = ["foo", "bar", "baz"]
736 
737 // filter out any non-number type:
738 a = filter(["foo", 1, true, null, 2.2], function(v) {
739     return (type(v) == "int" || type(v) == "double");
740 });
741 // a = [1, 2.2]
742 ```
743 
744 #### 6.10. `getenv([name])`
745 
746 Return the value of the given environment variable. If the variable name is
747 omitted, returns a dictionary containing all environment variables.
748 
749 #### 6.11. `hex(x)`
750 
751 Convert the given hexadecimal string into a number.
752 
753 #### 6.12. `index(arr_or_str, needle)`
754 
755 Find the given value passed as second argument within the array or string
756 specified in the first argument.
757 
758 Returns the first matching array index or first matching string offset or `-1`
759 if the value was not found.
760 
761 Returns `null` if the first argument was neither an array, nor a string.
762 
763 #### 6.13. `int(x)`
764 
765 Convert the given value to an integer. Returns `NaN` if the value is not
766 convertible.
767 
768 #### 6.14. `join(sep, arr)`
769 
770 Join the array passed as 2nd argument into a string, using the separator passed
771 in the first argument as glue. Returns `null` if the second argument is not an
772 array.
773 
774 #### 6.15. `keys(obj)`
775 
776 Return an array of all key names present in the passed object. Returns `null`
777 if the given argument is no object.
778 
779 #### 6.16. `lc(s)`
780 
781 Convert the given string to lowercase and return the resulting string.
782 Returns `null` if the given argument could not be converted to a string.
783 
784 #### 6.17. `length(x)`
785 
786 Return the length of the given object, array or string. Returns `null` if
787 the given argument is neither an object, array, nor a string.
788 
789 For objects, the length is defined as the number of keys within the object,
790 for arrays the length specifies the amount of contained items and for strings
791 it represents the number of contained bytes.
792 
793 ```javascript
794 length("test")                             // 4
795 length([true, false, null, 123, "test"])   // 5
796 length({foo: true, bar: 123, baz: "test"}) // 3
797 length({})                                 // 0
798 length(true)                               // null
799 length(10.0)                               // null
800 ```
801 
802 #### 6.18. `log(x)`
803 
804 Return the natural logarithm of x.
805 
806 #### 6.19. `ltrim(s, c)`
807 
808 Trim any of the specified characters in `c` from the start of `str`.
809 If the second argument is omitted, trims the characters ` ` (space), `\t`,
810 `\r` and `\n`.
811 
812 ```javascript
813 ltrim("  foo  \n")     // "foo  \n"
814 ltrim("--bar--", "-")  // "bar--"
815 ```
816 
817 #### 6.20. `map(arr, fn)`
818 
819 Transform the array passed as first argument by invoking the function specified
820 in the second argument for each array item.
821 
822 The result of the invoked function is put into the resulting array.
823 The map function is invoked with three arguments:
824 
825  1. The array value
826  2. The current index
827  3. The array being filtered
828 
829 Returns the transformed array.
830 
831 ```javascript
832 // turn into array of string lengths:
833 a = map(["Apple", "Banana", "Bean"], length)
834 // a = [5, 6, 4]
835 
836 // map to type names:
837 a = map(["foo", 1, true, null, 2.2], type);
838 // a = ["string", "int", "bool", null, "double"]
839 ```
840 
841 #### 6.21. `ord(s [, offset])`
842 
843 Without further arguments, this function returns the byte value of the first
844 character in the given string.
845 
846 If an offset argument is supplied, the byte value of the character at this
847 position is returned. If an invalid index is supplied, the function will
848 return `null`. Negative index entries are counted towards the end of the
849 string, e.g. `-2` will return the value of the second last character.
850 
851 ```javascript
852 ord("Abc");         // 65
853 ord("Abc", 0);      // 65
854 ord("Abc", 1);      // 98
855 ord("Abc", 2);      // 99
856 ord("Abc", 10);     // null
857 ord("Abc", -10);    // null
858 ord("Abc", "nan");  // null
859 ```
860 
861 #### 6.22. `pop(arr)`
862 
863 Pops the last item from the given array and returns it. Returns `null` if the
864 array was empty or if a non-array argument was passed.
865 
866 #### 6.23. `print(x, ...)`
867 
868 Print any of the given values to stdout. Arrays and objects are converted to
869 their JSON representation.
870 
871 Returns the amount of bytes printed.
872 
873 #### 6.24. `push(arr, v1, ...)`
874 
875 Push the given argument(s) to the given array. Returns the last pushed value.
876 
877 #### 6.25. `rand()`
878 
879 Returns a random number. If `srand()` has not been called already, it is
880 automatically invoked passing the current time as seed.
881 
882 #### 6.26. `reverse(arr_or_str)`
883 
884 If an array is passed, returns the array in reverse order. If a string is
885 passed, returns the string with the sequence of the characters reversed.
886 
887 Returns `null` if neither an array nor a string were passed.
888 
889 #### 6.27. `rindex(arr_or_str, needle)`
890 
891 Find the given value passed as second argument within the array or string
892 specified in the first argument.
893 
894 Returns the last matching array index or last matching string offset or `-1`
895 if the value was not found.
896 
897 Returns `null` if the first argument was neither an array, nor a string.
898 
899 #### 6.28. `rtrim(str, c)`
900 
901 Trim any of the specified characters in `c` from the end of `str`.
902 If the second argument is omitted, trims the characters, ` ` (space), `\t`,
903 `\r` and `\n`.
904 
905 ```javascript
906 rtrim("  foo  \n")     // "  foo"
907 rtrim("--bar--", "-")  // "--bar"
908 ```
909 
910 #### 6.29. `shift(arr)`
911 
912 Pops the first item from the given array and returns it. Returns `null` if the
913 array was empty or if a non-array argument was passed.
914 
915 #### 6.30. `sin(x)`
916 
917 Return the sine of x, where x is given in radians.
918 
919 #### 6.31. `sort(arr, fn)`
920 
921 Sort the given array according to the given sort function. If no sort
922 function is provided, a default ascending sort order is applied.
923 
924 ```javascript
925 sort([8, 1, 5, 9]) // [1, 5, 8, 9]
926 sort(["Bean", "Orange", "Apple"], function(a, b) {
927     return length(a) < length(b);
928 }) // ["Bean", "Apple", "Orange"]
929 ```
930 
931 #### 6.32. `splice(arr, off, len, ...)`
932 
933 Removes the elements designated by `off` and `len` from  the given an array,
934 and replaces them with the additional arguments passed, if any. Returns the
935 last element removed, or `null` if no elements are removed. The array grows
936 or shrinks as necessary.
937 
938 If `off` is negative then it starts that far from the end of the array. If
939 `len` is omitted, removes everything from `off` onward. If `len` is negative,
940 removes the elements from `off` onward except for `-len` elements at the end of
941 the array. If both `off` and `len` are omitted, removes everything.
942 
943 #### 6.33. `slice(arr[, off[, end]])`
944 
945 Performs a shallow copy of a portion of the source array, as specified by the
946 start and end offsets. Returns a new array containing the copied elements.
947 The original array is not modified.
948 
949 The `off` argument specifies the index of the first element to copy from the
950 source array while he `end` argument specifies the index of the first element
951 to exclude from the returned array, means the copied slice of the source array
952 spans from `off` (inclusive) to `end - 1`.
953 
954 If either `off` or `end` is negative then it starts that far from the end of
955 the array. If `off` is omitted it defaults to `0`, if end is omitted, it
956 defaults to the length of the source array. Either value is capped to the length
957 of the source array.
958 
959 Returns a new array containing the copied elements, if any.
960 
961 Returns `null` if the given source argument is not an array value.
962 
963 ```javascript
964 slice([1, 2, 3])          // [1, 2, 3]
965 slice([1, 2, 3], 1)       // [2, 3]
966 slice([1, 2, 3], -1)      // [3]
967 slice([1, 2, 3], -3, -1)  // [1, 2]
968 slice([1, 2, 3], 10)      // []
969 slice([1, 2, 3], 2, 1)    // []
970 slice("invalid", 1, 2)    // null
971 ```
972 
973 #### 6.34. `split(str, sep[, limit])`
974 
975 Split the given string using the separator passed as second argument and return
976 an array containing the resulting pieces.
977 
978 If a limit argument is supplied, the resulting array contains no more than the
979 given amount of entries, that means the string is split at most `limit - 1`
980 times total.
981 
982 The separator may either be a plain string or a regular expression.
983 
984 ```javascript
985 split("foo,bar,baz", ",")     // ["foo", "bar", "baz"]
986 split("foobar", "")           // ["f", "o", "o", "b", "a", "r"]
987 split("foo,bar,baz", /[ao]/)  // ["f", "", ",b", "r,b", "z"]
988 split("foo=bar=baz", "=", 2)  // ["foo", "bar=baz"]
989 ```
990 
991 #### 6.35. `sqrt(x)`
992 
993 Return the nonnegative square root of x.
994 
995 #### 6.36. `srand(n)`
996 
997 Seed the PRNG using the given number.
998 
999 #### 6.37. `substr(str, off, len)`
1000 
1001 Extracts a substring out of `str` and returns it. First character is at offset
1002 zero. If `off` is negative, starts that far back from the end of the string.
1003 If `len` is omitted, returns everything through the end of the string. If `len`
1004 is negative, leaves that many characters off the end of the string.
1005 
1006 ```javascript
1007 s = "The black cat climbed the green tree";
1008 
1009 substr(s, 4, 5);      // black
1010 substr(s, 4, -11);    // black cat climbed the
1011 substr(s, 14);        // climbed the green tree
1012 substr(s, -4);        // tree
1013 substr(s, -4, 2);     // tr
1014 ```
1015 
1016 #### 6.38. `time()`
1017 
1018 Returns the current UNIX epoch.
1019 
1020 ```javascript
1021 time();     // 1598043054
1022 ```
1023 
1024 #### 6.39. `trim()`
1025 
1026 Trim any of the specified characters in `c` from the start and end of `str`.
1027 If the second argument is omitted, trims the characters, ` ` (space), `\t`,
1028 `\r` and `\n`.
1029 
1030 ```javascript
1031 trim("  foo  \n")     // "foo"
1032 trim("--bar--", "-")  // "bar"
1033 ```
1034 
1035 #### 6.40. `type(x)`
1036 
1037 Returns the type of the given value as string which might be one of
1038 `"function"`, `"object"`, `"array"`, `"double"`, `"int"` or `"bool"`.
1039 
1040 Returns `null` when no value or `null` is passed.
1041 
1042 #### 6.41. `uchr(n1, ...)`
1043 
1044 Converts each given numeric value to an utf8 escape sequence and returns the
1045 resulting string. Invalid numeric values or values outside the range `0` ..
1046 `0x10FFFF` are represented by the unicode replacement character `0xFFFD`.
1047 
1048 ```javascript
1049 uchr(0x2600, 0x26C6, 0x2601);  // "☀⛆☁"
1050 uchr(-1, 0x20ffff, "foo");     // "���"
1051 ```
1052 
1053 #### 6.42. `uc(str)`
1054 
1055 Converts the given string to uppercase and return the resulting string.
1056 Returns `null` if the given argument could not be converted to a string.
1057 
1058 #### 6.43. `unshift(arr, v1, ...)`
1059 
1060 Add the given values to the beginning of the array passed as first argument.
1061 Returns the last value added to the array.
1062 
1063 #### 6.44. `values(obj)`
1064 
1065 Returns an array containing all values of the given object. Returns `null` if
1066 no object was passed.
1067 
1068 ```javascript
1069 values({ foo: true, bar: false });   // [true, false]
1070 ```
1071 
1072 #### 6.45. `printf(fmt, ...)`
1073 
1074 Formats the given arguments according to the given format string and outputs the
1075 result to stdout.
1076 
1077 Ucode supports a restricted subset of the formats allowed by the underlying
1078 libc's `printf()` implementation, namely it allows the `d`, `i`, `o`, `u`, `x`,
1079 `X`, `e`, `E`, `f`, `F`, `g`, `G`, `c` and `s` conversions.
1080 
1081 Additionally, an ucode specific `J` format is implemented, which causes the
1082 corresponding value to be formatted as JSON string. By prefixing the `J` format
1083 letter with a precision specifier, the resulting JSON output will be pretty
1084 printed. A precision of `0` will use tabs for indentation, any other positive
1085 precision will use that many spaces for indentation while a negative or omitted
1086 precision specifier will turn off pretty printing.
1087 
1088 Other format specifiers such as `n` or `z` are not accepted and returned
1089 verbatim. Format specifiers including `*` directives are rejected as
1090 well.
1091 
1092 ```javascript
1093 {%
1094   printf("Hello %s\n", "world");  // Hello world
1095   printf("%08x\n", 123);          // 0000007b
1096   printf("%c%c%c\n", 65, 98, 99); // Abc
1097   printf("%g\n", 10 / 3.0);       // 3.33333
1098   printf("%2$d %1$d\n", 12, 34);  // 34 12
1099   printf("%J", [1,2,3]);          // [ 1, 2, 3 ]
1100 
1101   printf("%.J", [1,2,3]);
1102   // [
1103   //         1,
1104   //         2,
1105   //         3
1106   // ]
1107 
1108   printf("%.2J", [1,2,3]);
1109   // [
1110   //   1,
1111   //   2,
1112   //   3
1113   // ]
1114 %}
1115 ```
1116 
1117 #### 6.46. `sprintf(fmt, ...)`
1118 
1119 Formats the given arguments according to the given format string and returns the
1120 resulting string.
1121 
1122 See `printf()` for details.
1123 
1124 #### 6.47. `match(str, /pattern/)`
1125 
1126 Match the given string against the regular expression pattern specified as
1127 second argument.
1128 
1129 If the passed regular expression uses the `g` flag, the return value will be an
1130 array of arrays describing all found occurences within the string.
1131 
1132 Without the `g` modifier, an array describing the first match is returned.
1133 Returns `null` if the pattern was not found within the given string.
1134 
1135 ```javascript
1136 match("foobarbaz", /b.(.)/)   // ["bar", "r"]
1137 match("foobarbaz", /b.(.)/g)  // [["bar", "r"], ["baz", "z"]]
1138 ```
1139 
1140 #### 6.48. `replace(str, /pattern/, replace[, limit])`
1141 
1142 Replace occurences of the specified pattern in the string passed as first
1143 argument. The pattern value may be either a regular expression or a plain
1144 string. The replace value may be a function which is invoked for each found
1145 pattern or any other value which is converted into a plain string and used as
1146 replacement.
1147 
1148 When an optional limit is specified, substitutions are performed only that
1149 many times.
1150 
1151 If the pattern is a regular expression and not using the `g` flag, then only the
1152 first occurence in the string is replaced, if the `g` flag is used or if the
1153 pattern is not a regular expression, all occurrences are replaced.
1154 
1155 If the replace value is a callback function, it is invoked with the found
1156 substring as first and any capture group values as subsequent parameters.
1157 
1158 If the replace value is a string, the following special substrings are
1159 substituted before it is inserted into the result:
1160 
1161  - `$$` - replaced by a literal `$`
1162  - ``$` `` - replaced by the text before the match
1163  - `$'` - replaced by the text after the match
1164  - `$&` - replaced by the matched substring
1165  - `$1`..`$9` - replaced by the value of the corresponding capture group, if the capture group is not defined, it is not substituted
1166 
1167 ```javascript
1168 replace("barfoobaz", /(f)(o+)/g, "[$$|$`|$&|$'|$1|$2|$3]")  // bar[$|bar|foo|baz|f|oo|$3]baz
1169 replace("barfoobaz", /(f)(o+)/g, uc)                        // barFOObaz
1170 replace("barfoobaz", "a", "X")                              // bXrfoobXz
1171 replace("barfoobaz", /(.)(.)(.)/g, function(m, c1, c2, c3) {
1172     return c3 + c2 + c1;
1173 })                                                          // raboofzab
1174 replace("aaaaa", "a", "x", 3)                               // xxxaa
1175 replace("foo bar baz", /[ao]/g, "x", 3)                     // fxx bxr baz
1176 ```
1177 
1178 #### 6.49. `json(str)`
1179 
1180 Parse the given string as JSON and return the resulting value. Throws an
1181 exception on parse errors, trailing garbage or premature EOF.
1182 
1183 ```javascript
1184 json('{"a":true, "b":123}')   // { "a": true, "b": 123 }
1185 json('[1,2,')                 // Throws exception
1186 ```
1187 
1188 #### 6.50. `include(path[, scope])`
1189 
1190 Evaluate and include the file at the given path and optionally override the
1191 execution scope with the given scope object.
1192 
1193 By default, the file is executed within the same scope as the calling
1194 `include()` but by passing an object as second argument, it is possible to
1195 extend the scope available to the included file. This is useful to supply
1196 additional properties as global variables to the included code.
1197 
1198 To sandbox included code, that is giving it only access to explicitely
1199 provided properties, the `proto()` function can be used to create a scope
1200 object with an empty prototype. See the examples below for details.
1201 
1202 If the given path argument is not absolute, it is interpreted relative to the
1203 directory of the current template file, that is the file that is invoking the
1204 `include()` function.
1205 
1206 If the ucode interpreter executes program code from stdin, the given path is
1207 interpreted relative to the current working directory of the process.
1208 
1209 ```javascript
1210 // Load and execute "foo.uc" immediately
1211 include("./foo.uc")
1212 
1213 // Execute the "supplemental.ucode" in an extended scope and make the "foo" and
1214 // "bar" properties available as global variables
1215 include("./supplemental.uc", {
1216   foo: true,
1217   bar: 123
1218 })
1219 
1220 // Execute the "untrusted.ucode" in a sandboxed scope and make the "foo" and
1221 // "bar" variables as well as the "print" function available to it. By assigning
1222 // an empty prototype object to the scope, included code has no access to
1223 // other global values anymore
1224 include("./untrusted.uc", proto({
1225   foo: true,
1226   bar: 123,
1227   print: print
1228 }, {}))
1229 ```
1230 
1231 #### 6.51. `warn(x, ...)`
1232 
1233 Print any of the given values to stderr. Arrays and objects are converted to
1234 their JSON representation.
1235 
1236 Returns the amount of bytes printed.
1237 
1238 #### 6.52. `system(command, timeout)`
1239 
1240 Executes the given command, waits for completion and returns the resulting
1241 exit code.
1242 
1243 The command argument may be either a string, in which case it is passed to
1244 `/bin/sh -c`, or an array, which is directly converted into an `execv()`
1245 argument vector.
1246 
1247 If the program terminated normally, a positive integer holding the programs
1248 `exit()` code is returned. If the program was terminated by an uncatched
1249 signal, a negative signal number is returned, e.g. `-9` when the program was
1250 terminated by `SIGKILL`.
1251 
1252 If the optional timeout argument is specified, the program is terminated by
1253 `SIGKILL` after that many milliseconds when it didn't complete within the timeout.
1254 
1255 Omitting the timeout argument, or passing `0` disables the command timeout.
1256 
1257 ```javascript
1258 // Execute through `/bin/sh`
1259 system("echo 'Hello world' && exit 3");    // prints "Hello world" to stdout and returns 3
1260 
1261 // Execute argument vector
1262 system(["/usr/bin/date", "+%s"]);          // prints the UNIX timestamp to stdout and returns 0
1263 
1264 // Apply a timeout
1265 system("sleep 3 && echo 'Success'", 1000); // returns -9
1266 ```
1267 
1268 #### 6.53. `trace(level)`
1269 
1270 Enables or disables VM opcode tracing. When invoked with a positive non-zero
1271 level, opcode tracing is enabled and debug information is printed to stderr
1272 as the program is executed.
1273 
1274 Invoking `trace()` with zero as argument will turn off opcode tracing.
1275 
1276 Right now, any positive non-zero value will enable tracing while future
1277 implementation might provide different different verbosity levels or treat
1278 the level argument as bit mask to enable or disable individual debug
1279 elements.
1280 
1281 #### 6.54. `proto(val[, proto])`
1282 
1283 Get or set the prototype of the array or object value `val`.
1284 
1285 When invoked without a second argument, the function returns the current
1286 prototype of the value in `val` or `null` if there is no prototype or if
1287 the given value is neither an object, nor an array.
1288 
1289 When invoked with a second prototype argument, the given `proto` value is
1290 set as prototype on the array or object in `val`.
1291 
1292 Throws an exception if the given prototype value is not an object.
1293 
1294 #### 6.55. `sleep(milliseconds)`
1295 
1296 Pause execution for the given amount of milliseconds. Returns `false` if
1297 an invalid value was passed, otherwise `true`.
1298 
1299 #### 6.56. `assert(cond[, message])`
1300 
1301 Raise an exception with the given `message` parameter if the value in `cond`
1302 is not truish. When `message` is omitted, the default value is `Assertion failed`.
1303 
1304 #### 6.57. `render(path_or_func[, scope_or_fnarg1 [, fnarg2 [, ...]]])`
1305 
1306 When invoked with a string value as first argument, the function acts like
1307 like `include()` but captures the output of the included file as string and
1308 returns the captured contents. The second argument is treated as scope. See
1309 `include()` for details on scoping.
1310 
1311 When invoked with a function value as first argument, `render()` calls the
1312 given function and passes all subsequent arguments to it. Any output
1313 (through print(), template text instructions and the like) produced by the
1314 called function is captured and returned as string. The return value of the
1315 called function is discarded.
1316 
1317 #### 6.58. `regexp(source[, flags])`
1318 
1319 Construct a regular expression instance from the given `source` pattern string
1320 and any flags optionally specified by the `flags` argument.
1321 
1322 Throws a type error exception if `flags` is not a string or if the string in
1323 `flags` contains unrecognized regular expression flag characters.
1324 
1325 Throws a syntax error when the pattern in `source` cannot be compiled into a
1326 valid regular expression by the underlying C runtimes `regcomp(3)` function.
1327 
1328 Returns the compiled regular expression value.
1329 
1330 ```javascript
1331 regexp('foo.*bar', 'is');   // equivalent to /foo.*bar/is
1332 regexp('foo.*bar', 'x');    // throws "Type error: Unrecognized flag character 'x'"
1333 regexp('foo.*(');           // throws "Syntax error: Unmatched ( or \("
1334 ```
1335 
1336 #### 6.59. `wildcard(subject, pattern[, nocase])`
1337 
1338 Match the given subject against the supplied wildcard (file glob) pattern.
1339 
1340 If a truish value is supplied as 3rd argument, case insensitive matching is
1341 performed. If a non-string value is supplied as subject, it is converted into
1342 a string before being matched.
1343 
1344 Returns `true` when the subject matches the pattern or `false` when not.
1345 
1346 #### 6.60. `sourcepath([depth [, dironly]])`
1347 
1348 Determine the path of the source file currently being executed by ucode.
1349 
1350 The optional `depth` parameter allows walking up the call stack to determine
1351 the path of the parent sources including or requiring the current source file.
1352 If unspecified, the `depth` defaults to `0`, that is the currently executed
1353 file.
1354 
1355 If a truish value is passed in `dironly`, only the directory portion of the
1356 source file path is returned.
1357 
1358 If the ucode interpreter executes code from stdin or a code fragment passed
1359 via `-s` switch, the function returns `null` since there is no associated
1360 file path.
1361 
1362 If `depth` exceeds the size of the call stack, the function returns `null`
1363 as well.
1364 
1365 #### 6.61. `min([val1 [, val2 [, ...]]])`
1366 
1367 Return the smallest value among all parameters passed to the function.
1368 The function does a `val1 < val2` comparison internally, which means that
1369 the same value coercion rules as for relational operators apply. If both
1370 strings and numbers are passed to `min()`, then any string values will be
1371 effectively ignored since both `1 < "abc"` and `1 > "abc"` comparisons
1372 yield false results.
1373 
1374 ```javascript
1375 min(5, 2.1, 3, "abc", 0.3);   // 0.3
1376 min(1, "abc");                // 1
1377 min("1", "abc");              // "1"
1378 min("def", "abc", "ghi");     // "abc"
1379 min(true, false);             // false
1380 ```
1381 
1382 #### 6.62. `max([val1 [, val2 [, ...]]])`
1383 
1384 Return the largest value among all parameters passed to the function.
1385 The function does a `val1 > val2` comparison internally, which means that
1386 the same value coercion rules as for relational operators apply. If both
1387 strings and numbers are passed to `min()`, then any string values will be
1388 effectively ignored since both `1 < "abc"` and `1 > "abc"` comparisons
1389 yield false results.
1390 
1391 ```javascript
1392 max(5, 2.1, 3, "abc", 0.3);   // 5
1393 max(1, "abc");                // 1 (!)
1394 max("1", "abc");              // "abc"
1395 max("def", "abc", "ghi");     // "ghi"
1396 max(true, false);             // true
1397 ```
1398 
1399 #### 6.63. `b64dec(str)`
1400 
1401 Decodes the given base64 encoded string and returns the decoded result, any
1402 whitespace in the input string is ignored.
1403 
1404 If non-whitespace, non-base64 characters are encountered, if invalid padding
1405 or trailing garbage is found, the function returns `null`.
1406 
1407 If a non-string argument is given, the function returns `null`.
1408 
1409 ```javascript
1410 b64dec("VGhpcyBpcyBhIHRlc3Q=");   // "This is a test"
1411 b64dec(123);                      // null
1412 b64dec("XXX");                    // null
1413 ```
1414 
1415 #### 6.64. `b64enc(str)`
1416 
1417 Encodes the given string into base64 and returns the resulting encoded
1418 string.
1419 
1420 If a non-string argument is given, the function returns `null`.
1421 
1422 ```javascript
1423 b64enc("This is a test");         // "VGhpcyBpcyBhIHRlc3Q="
1424 b64enc(123);                      // null
1425 ```
1426 
1427 #### 6.65. `uniq(array)`
1428 
1429 Returns a new array containing all unique values of the given input
1430 array. The order is preserved, that is subsequent duplicate values
1431 are simply skipped.
1432 
1433 If a non-array argument is given, the function returns `null`.
1434 
1435 ```javascript
1436 uniq([ 1, true, "foo", 2, true, "bar", "foo" ]); // [ 1, true, "foo", 2, "bar" ]
1437 uniq("test");                                    // null
1438 ```
1439 
1440 #### 6.66. `localtime([epoch])`
1441 
1442 Return the given epoch timestamp (or now, if omitted) as a dictionary
1443 containing broken-down date and time information according to the local
1444 system timezone.
1445 
1446 The resulting dictionary contains the following fields:
1447 
1448  - `sec`    Seconds (0-60)
1449  - `min`    Minutes (0-59)
1450  - `hour`   Hours (0-23)
1451  - `mday`   Day of month (1-31)
1452  - `mon`    Month (1-12)
1453  - `year`   Year (>= 1900)
1454  - `wday`   Day of the week (1-7, Sunday = 7)
1455  - `yday`   Day of the year (1-366, Jan 1st = 1)
1456  - `isdst`  Daylight saving time in effect (yes = 1)
1457 
1458 Note that in contrast to the underlying `localtime(3)` C library function,
1459 the values for `mon`, `wday` and `yday` are 1-based and the `year` is
1460 1900-based.
1461 
1462 ```javascript
1463 localtime(1647953502);
1464 // {
1465 //         "sec": 42,
1466 //         "min": 51,
1467 //         "hour": 13,
1468 //         "mday": 22,
1469 //         "mon": 3,
1470 //         "year": 2022,
1471 //         "wday": 2,
1472 //         "yday": 81,
1473 //         "isdst": 0
1474 // }
1475 ```
1476 
1477 #### 6.67. `gmtime([epoch])`
1478 
1479 Like `localtime()` but interpreting the given epoch value as UTC time.
1480 
1481 See `localtime()` for details on the return value.
1482 
1483 #### 6.68. `timelocal(datetimespec)`
1484 
1485 Performs the inverse operation of `localtime()` by taking a broken-down
1486 date and time dictionary and transforming it into an epoch value according
1487 to the local system timezone.
1488 
1489 The `wday` and `yday` fields of the given date time specification are
1490 ignored. Field values outside of their valid range are internally normalized,
1491 e.g. October 40th is interpreted as November 9th.
1492 
1493 Returns the resulting epoch value or null if the input date time dictionary
1494 was invalid or if the date time specification cannot be represented as
1495 epoch value.
1496 
1497 ```javascript
1498 timelocal({ "sec": 42, "min": 51, "hour": 13, "mday": 22, "mon": 3, "year": 2022, "isdst": 0 })
1499 // 1647953502
1500 ```
1501 
1502 #### 6.69. `timegm(datetimespec)`
1503 
1504 Like `timelocal()` but interpreting the given date time specification as
1505 UTC time.
1506 
1507 See `timelocal()` for details.
1508 
1509 #### 6.70. `clock([monotonic])`
1510 
1511 Reads the current second and microsecond value of the system clock.
1512 
1513 By default, the realtime clock is queried which might skew forwards
1514 or backwards due to NTP changes, system sleep modes etc.
1515 
1516 If a truish value is passed as argument, the monotonic system clock
1517 is queried instead, which will return the monotonically increasing
1518 time since some arbitrary point in the past (usually the system boot
1519 time).
1520 
1521 Returns a two element array containing the full seconds as first and
1522 the nanosecond fraction as second element.
1523 
1524 Returns `null` if a monotonic clock value is requested and the system
1525 does not implement this clock type.
1526 
1527 ```javascript
1528 clock();        // [ 1647954926, 798269464 ]
1529 clock(true);    // [ 474751, 527959975 ]
1530 ```
1531 
1532 #### 6.71. `hexdec(hexstring[, skipchars])`
1533 
1534 The `hexdec()` function decodes the given hexadecimal digit string into
1535 a byte string, optionally skipping specified characters.
1536 
1537 If the characters to skip are not specified, a default of `" \t\n"` is
1538 used.
1539 
1540 Returns null if the input string contains invalid characters or an uneven
1541 amount of hex digits.
1542 
1543 Returns the decoded byte string on success.
1544 
1545 ```javascript
1546 hexdec("48656c6c6f20776f726c64210a");  // "Hello world!\n"
1547 hexdec("44:55:66:77:33:44", ":");      // "DUfw3D"
1548 ```
1549 
1550 #### 6.72. `hexenc(val)`
1551 
1552 The `hexenc()` function encodes the given byte string into a hexadecimal
1553 digit string, converting the input value to a string if needed.
1554 
1555 Returns the encoded hexadecimal digit string.
1556 
1557 ```javascript
1558 hexenc("Hello world!\n");   // "48656c6c6f20776f726c64210a"
1559 ```
1560 
1561 #### 6.73. `gc([operation[, argument]])`
1562 
1563 The `gc()` function allows interaction with the mark and sweep garbage
1564 collector of the running ucode virtual machine.
1565 
1566 Depending on the given `operation` string argument, the meaning of
1567 `argument` and the function return value differs.
1568 
1569 The following operations are defined:
1570 
1571  - `collect` - Perform a complete garbage collection cycle, returns `true`.
1572  - `start` - (Re-)start periodic garbage collection, `argument` is an optional
1573              integer in the range 1..65535 specifying the interval. Defaults
1574              to `1000` if omitted. Returns `true` if the periodic GC was
1575              previously stopped and is now started or if the interval changed.
1576              Returns `false` otherwise.
1577  - `stop` - Stop periodic garbage collection. Returns `true` if the periodic GC
1578             was previously started and is now stopped, `false` otherwise.
1579  - `count` - Count the amount of active complex object references in the VM
1580              context, returns the counted amount.
1581 
1582 If the `operation` argument is omitted, the default is `collect`.
1583 
1584 Returns `null` if a non-string `operation` value is given.
1585 
1586 #### 6.74. `loadstring(code[, options])`
1587 
1588 Compiles the given code string into a ucode program and returns the resulting
1589 program entry function. The optinal `options` dictionary allows overriding
1590 parse and compile options.
1591 
1592 If a non-string `code` argument is given, it is implicitly converted to a
1593 string value first.
1594 
1595 If `options` is omitted or a non-object value, the compile options of the
1596 running ucode program are reused.
1597 
1598 The following keys in the `options` dictionary are recognized:
1599 
1600 | Key                   | Type  | Description                                              |
1601 |-----------------------|-------|----------------------------------------------------------|
1602 | `lstrip_blocks`       | bool  | Strip leading whitespace before statement template blocks|
1603 | `trim_blocks`         | bool  | Strip newline after statement template blocks            |
1604 | `strict_declarations` | bool  | Treat access to undefined variables as fatal error       |
1605 | `raw_mode`            | bool  | Compile source in script mode, don't treat it as template|
1606 | `module_search_path`  | array | Override compile time module search path                 |
1607 | `force_dynlink_list`  | array | List of module names to treat as dynamic extensions      |
1608 
1609 Unrecognized keys are ignored, unspecified options default to those of the
1610 running program.
1611 
1612 Returns the compiled program entry function.
1613 
1614 Throws an exception on compilation errors.
1615 
1616 ```javascript
1617 let fn1 = loadstring("Hello, {{ name }}", { raw_mode: false });
1618 
1619 global.name = "Alice";
1620 fn1(); // prints `Hello, Alice`
1621 
1622 
1623 let fn2 = loadstring("return 1 + 2;", { raw_mode: true });
1624 fn2(); // 3
1625 ```
1626 
1627 #### 6.75. `loadfile(path[, options])`
1628 
1629 Compiles the given file into a ucode program and returns the resulting program
1630 entry function.
1631 
1632 See `loadstring()` for details.
1633 
1634 Returns the compiled program entry function.
1635 
1636 Throws an exception on compilation or file i/o errors.
1637 
1638 ```javascript
1639 loadfile("./templates/example.uc");  // function main() { ... }
1640 ```
1641 
1642 #### 6.76. `call(fn[, ctx[, scope[, arg1[, ...]]]])`
1643 
1644 Calls the given function value with a modified environment. The given `ctx`
1645 argument is used as `this` context for the invoked function and the given
1646 `scope` value as global environment. Any further arguments are passed to the
1647 invoked function as-is.
1648 
1649 When `ctx` is omitted or `null`, the function will get invoked with `this`
1650 being `null`.
1651 
1652 When `scope` is omitted or `null`, the function will get executed with the
1653 current global environment of the running program. When `scope` is set to a
1654 dictionary, the dictionary is used as global function environment.
1655 
1656 When the `scope` dictionary has no prototype, the current global environment
1657 will be set as prototype, means the scope will inherit from it. When a scope
1658 prototype is set, it is kept. This allows passing an isolated (sandboxed)
1659 function scope without access to the global environment.
1660 
1661 Any further argument is forwarded as-is to the invoked function as function
1662 call argument.
1663 
1664 Returns `null` if the given function value `fn` is not callable.
1665 
1666 Returns the return value of the invoked function in all other cases.
1667 
1668 Forwards exceptions thrown by the invoked function.
1669 
1670 ```javascript
1671 // Override this context
1672 call(function() { printf("%J\n", this) });            // null
1673 call(function() { printf("%J\n", this) }, null);      // null
1674 call(function() { printf("%J\n", this) }, { x: 1 });  // { "x": 1 }
1675 call(function() { printf("%J\n", this) }, { x: 2 });  // { "x": 2 }
1676 
1677 // Run with default scope
1678 global.a = 1;
1679 call(function() { printf("%J\n", a) });                  // 1
1680 
1681 // Override scope, inherit from current global scope (implicit)
1682 call(function() { printf("%J\n", a) }, null, { a: 2 });  // 2
1683 
1684 // Override scope, inherit from current global scope (explicit)
1685 call(function() { printf("%J\n", a) }, null,
1686         proto({ a: 2 }, global));                        // 2
1687 
1688 // Override scope, don't inherit (pass `printf()` but not `a`)
1689 call(function() { printf("%J\n", a) }, null,
1690         proto({}, { printf }));                          // null
1691 
1692 // Forward arguments
1693 x = call((x, y, z) => x * y * z, null, null, 2, 3, 4);   // x = 24
1694 ```

This page was automatically generated by LXR 0.3.1.  •  OpenWrt