• 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
 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 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 or false respectively.
591 
592 In the case of `&&` the rightmost value is returned while `||` results in the
593 first truish value.
594 
595 The unary `!` operator will result in `true` if the operand is not treish,
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(!false);         // true
608   print(!true);          // false
609 
610   res = test1() && test2();  // test2() is only called if test1() returns true
611 %}
612 ```
613 
614 #### 5.5. Assignment operations
615 
616 In addition to the basic assignment operator `=`, most other operators have a
617 corresponding shortcut assignment operator which reads the specified variable,
618 applies the operation and operand to it, and writes it back.
619 
620 The result of assignment expressions is the assigned value.
621 
622 ```javascript
623 {%
624   a = 1;     // assign 1 to variable a
625   a += 2;    // a = a + 2;
626   a -= 3;    // a = a - 3;
627   a *= 4;    // a = a * 4;
628   a /= 5;    // a = a / 5;
629   a %= 6;    // a = a % 6;
630   a &= 7;    // a = a & 7;
631   a |= 8;    // a = a | 8;
632   a ^= 9;    // a = a ^ 9;
633   a <<= 10;  // a = a << 10;
634   a >>= 11;  // a = a >> 11;
635 
636   print(a = 2);  // 2
637 %}
638 ```
639 
640 #### 5.6. Miscellaneous operators
641 
642 Besides the operators described so far, ucode script also supports a `delete`
643 operator which removes a property from an object value.
644 
645 ```javascript
646 {%
647   a = { test: true };
648 
649   delete a.test;         // true
650   delete a.notexisting;  // false
651 
652   print(a);              // { }
653 %}
654 ```
655 
656 ### 6. Functions
657 
658 Ucode scripts may call a number of built-in functions to manipulate values or
659 to output information.
660 
661 #### 6.1. `abs(x)`
662 
663 Returns the absolute value of the given operand. Results in `NaN` if operand is
664 not convertible to number.
665 
666 ```javascript
667 abs(1);        // 1
668 abs(-2);       // 2
669 abs(-3.5);     // 3.5
670 abs("0x123");  // 291
671 abs("-0x123"); // NaN
672 abs([]);       // NaN
673 ```
674 
675 #### 6.2. `atan2(x, y)`
676 
677 Calculates the principal value of the arc tangent of x/y, using the signs of
678 the two arguments to determine the quadrant of the result.
679 
680 #### 6.3. `chr(n1, ...)`
681 
682 Converts each given numeric value to a byte and return the resulting string.
683 Invalid numeric values or values < 0 result in `\0` bytes, values larger than
684 255 are truncated to 255.
685 
686 ```javascript
687 chr(65, 98, 99);  // "Abc"
688 chr(-1, 300);     // string consisting of an `0x0` and a `0xff` byte
689 ```
690 
691 #### 6.4. `cos(x)`
692 
693 Return the cosine of x, where x is given in radians.
694 
695 #### 6.5. `die(msg)`
696 
697 Raise an exception with the given message and abort execution.
698 
699 #### 6.6. `exists(obj, key)`
700 
701 Return `true` if the given key is present within the object passed as first
702 argument, otherwise `false`.
703 
704 #### 6.7. `exit(n)`
705 
706 Terminate the interpreter with the given exit code.
707 
708 #### 6.8. `exp(n)`
709 
710 Return the value of e (the base of natural logarithms) raised to the power
711 of n.
712 
713 #### 6.9. `filter(arr, fn)`
714 
715 Filter the array passed as first argument by invoking the function specified
716 in the second argument for each array item.
717 
718 If the invoked function returns a truish result, the item is retained,
719 otherwise it is dropped. The filter function is invoked with three arguments:
720 
721  1. The array value
722  2. The current index
723  3. The array being filtered
724 
725 Returns the filtered array.
726 
727 ```javascript
728 // filter out any empty string:
729 a = filter(["foo", "", "bar", "", "baz"], length)
730 // a = ["foo", "bar", "baz"]
731 
732 // filter out any non-number type:
733 a = filter(["foo", 1, true, null, 2.2], function(v) {
734     return (type(v) == "int" || type(v) == "double");
735 });
736 // a = [1, 2.2]
737 ```
738 
739 #### 6.10. `getenv([name])`
740 
741 Return the value of the given environment variable. If the variable name is
742 omitted, returns a dictionary containing all environment variables.
743 
744 #### 6.11. `hex(x)`
745 
746 Convert the given hexadecimal string into a number.
747 
748 #### 6.12. `index(arr_or_str, needle)`
749 
750 Find the given value passed as second argument within the array or string
751 specified in the first argument.
752 
753 Returns the first matching array index or first matching string offset or `-1`
754 if the value was not found.
755 
756 Returns `null` if the first argument was neither an array, nor a string.
757 
758 #### 6.13. `int(x)`
759 
760 Convert the given value to an integer. Returns `NaN` if the value is not
761 convertible.
762 
763 #### 6.14. `join(sep, arr)`
764 
765 Join the array passed as 2nd argument into a string, using the separator passed
766 in the first argument as glue. Returns `null` if the second argument is not an
767 array.
768 
769 #### 6.15. `keys(obj)`
770 
771 Return an array of all key names present in the passed object. Returns `null`
772 if the given argument is no object.
773 
774 #### 6.16. `lc(s)`
775 
776 Convert the given string to lowercase and return the resulting string.
777 Returns `null` if the given argument could not be converted to a string.
778 
779 #### 6.17. `length(x)`
780 
781 Return the length of the given object, array or string. Returns `null` if
782 the given argument is neither an object, array, nor a string.
783 
784 For objects, the length is defined as the number of keys within the object,
785 for arrays the length specifies the amount of contained items and for strings
786 it represents the number of contained bytes.
787 
788 ```javascript
789 length("test")                             // 4
790 length([true, false, null, 123, "test"])   // 5
791 length({foo: true, bar: 123, baz: "test"}) // 3
792 length({})                                 // 0
793 length(true)                               // null
794 length(10.0)                               // null
795 ```
796 
797 #### 6.18. `log(x)`
798 
799 Return the natural logarithm of x.
800 
801 #### 6.19. `ltrim(s, c)`
802 
803 Trim any of the specified characters in `c` from the start of `str`.
804 If the second argument is omitted, trims the characters, ` ` (space), `\t`,
805 `\r` and `\n`.
806 
807 ```javascript
808 ltrim("  foo  \n")     // "foo  \n"
809 ltrim("--bar--", "-")  // "bar--"
810 ```
811 
812 #### 6.20. `map(arr, fn)`
813 
814 Transform the array passed as first argument by invoking the function specified
815 in the second argument for each array item.
816 
817 The result of the invoked function is put into the resulting array.
818 The map function is invoked with three arguments:
819 
820  1. The array value
821  2. The current index
822  3. The array being filtered
823 
824 Returns the transformed array.
825 
826 ```javascript
827 // turn into array of string lengths:
828 a = map(["Apple", "Banana", "Bean"], length)
829 // a = [5, 6, 4]
830 
831 // map to type names:
832 a = map(["foo", 1, true, null, 2.2], type);
833 // a = ["string", "int", "bool", null, "double"]
834 ```
835 
836 #### 6.21. `ord(s [, offset])`
837 
838 Without further arguments, this function returns the byte value of the first
839 character in the given string.
840 
841 If an offset argument is supplied, the byte value of the character at this
842 position is returned. If an invalid index is supplied, the function will
843 return `null`. Negative index entries are counted towards the end of the
844 string, e.g. `-2` will return the value of the second last character.
845 
846 ```javascript
847 ord("Abc");         // 65
848 ord("Abc", 0);      // 65
849 ord("Abc", 1);      // 98
850 ord("Abc", 2);      // 99
851 ord("Abc", 10);     // null
852 ord("Abc", -10);    // null
853 ord("Abc", "nan");  // null
854 ```
855 
856 #### 6.22. `pop(arr)`
857 
858 Pops the last item from the given array and returns it. Returns `null` if the
859 array was empty or if a non-array argument was passed.
860 
861 #### 6.23. `print(x, ...)`
862 
863 Print any of the given values to stdout. Arrays and objects are converted to
864 their JSON representation.
865 
866 Returns the amount of bytes printed.
867 
868 #### 6.24. `push(arr, v1, ...)`
869 
870 Push the given argument(s) to the given array. Returns the last pushed value.
871 
872 #### 6.25. `rand()`
873 
874 Returns a random number. If `srand()` has not been called already, it is
875 automatically invoked passing the current time as seed.
876 
877 #### 6.26. `reverse(arr_or_str)`
878 
879 If an array is passed, returns the array in reverse order. If a string is
880 passed, returns the string with the sequence of the characters reversed.
881 
882 Returns `null` if neither an array nor a string were passed.
883 
884 #### 6.27. `rindex(arr_or_str, needle)`
885 
886 Find the given value passed as second argument within the array or string
887 specified in the first argument.
888 
889 Returns the last matching array index or last matching string offset or `-1`
890 if the value was not found.
891 
892 Returns `null` if the first argument was neither an array, nor a string.
893 
894 #### 6.28. `rtrim(str, c)`
895 
896 Trim any of the specified characters in `c` from the end of `str`.
897 If the second argument is omitted, trims the characters, ` ` (space), `\t`,
898 `\r` and `\n`.
899 
900 ```javascript
901 rtrim("  foo  \n")     // "  foo"
902 rtrim("--bar--", "-")  // "--bar"
903 ```
904 
905 #### 6.29. `shift(arr)`
906 
907 Pops the first item from the given array and returns it. Returns `null` if the
908 array was empty or if a non-array argument was passed.
909 
910 #### 6.30. `sin(x)`
911 
912 Return the sine of x, where x is given in radians.
913 
914 #### 6.31. `sort(arr, fn)`
915 
916 Sort the given array according to the given sort function. If no sort
917 function is provided, a default ascending sort order is applied.
918 
919 ```javascript
920 sort([8, 1, 5, 9]) // [1, 5, 8, 9]
921 sort(["Bean", "Orange", "Apple"], function(a, b) {
922     return length(a) < length(b);
923 }) // ["Bean", "Apple", "Orange"]
924 ```
925 
926 #### 6.32. `splice(arr, off, len, ...)`
927 
928 Removes the elements designated by `off` and `len` from  the given an array,
929 and replaces them with the additional arguments passed, if any. Returns the
930 last element removed, or `null` if no elements are removed. The array grows or shrinks as necessary.
931 
932 If `off` is negative then it starts that far from the end of the array. If
933 `len` is omitted, removes everything from `off` onward. If `len` is negative,
934 removes the elements from `off` onward except for `-len` elements at the end of
935 the array. If both `off` and `len` are omitted, removes everything.
936 
937 #### 6.33. `split(str, sep[, limit])`
938 
939 Split the given string using the separator passed as second argument and return
940 an array containing the resulting pieces.
941 
942 If a limit argument is supplied, the resulting array contains no more than the
943 given amount of entries, that means the string is split at most `limit - 1`
944 times total.
945 
946 The separator may either be a plain string or a regular expression.
947 
948 ```javascript
949 split("foo,bar,baz", ",")     // ["foo", "bar", "baz"]
950 split("foobar", "")           // ["f", "o", "o", "b", "a", "r"]
951 split("foo,bar,baz", /[ao]/)  // ["f", "", ",b", "r,b", "z"]
952 split("foo=bar=baz", "=", 2)  // ["foo", "bar=baz"]
953 ```
954 
955 #### 6.34. `sqrt(x)`
956 
957 Return the nonnegative square root of x.
958 
959 #### 6.35. `srand(n)`
960 
961 Seed the PRNG using the given number.
962 
963 #### 6.36. `substr(str, off, len)`
964 
965 Extracts a substring out of `str` and returns it. First character is at offset
966 zero. If `off` is negative, starts that far back from the end of the string.
967 If `len` is omitted, returns everything through the end of the string. If `len`
968 is negative, leaves that many characters off the end of the string.
969 
970 ```javascript
971 s = "The black cat climbed the green tree";
972 
973 substr(s, 4, 5);      // black
974 substr(s, 4, -11);    // black cat climbed the
975 substr(s, 14);        // climbed the green tree
976 substr(s, -4);        // tree
977 substr(s, -4, 2);     // tr
978 ```
979 
980 #### 6.37. `time()`
981 
982 Returns the current UNIX epoch.
983 
984 ```javascript
985 time();     // 1598043054
986 ```
987 
988 #### 6.38. `trim()`
989 
990 Trim any of the specified characters in `c` from the start and end of `str`.
991 If the second argument is omitted, trims the characters, ` ` (space), `\t`,
992 `\r` and `\n`.
993 
994 ```javascript
995 ltrim("  foo  \n")     // "foo"
996 ltrim("--bar--", "-")  // "bar"
997 ```
998 
999 #### 6.39. `type(x)`
1000 
1001 Returns the type of the given value as string which might be one of
1002 `"function"`, `"object"`, `"array"`, `"double"`, `"int"` or `"bool"`.
1003 
1004 Returns `null` when no value or `null` is passed.
1005 
1006 #### 6.40. `uchr(n1, ...)`
1007 
1008 Converts each given numeric value to an utf8 escape sequence and returns the
1009 resulting string. Invalid numeric values or values outside the range `0` ..
1010 `0x10FFFF` are represented by the unicode replacement character `0xFFFD`.
1011 
1012 ```javascript
1013 uchr(0x2600, 0x26C6, 0x2601);  // "☀⛆☁"
1014 uchr(-1, 0x20ffff, "foo");     // "���"
1015 ```
1016 
1017 #### 6.41. `uc(str)`
1018 
1019 Converts the given string to uppercase and return the resulting string.
1020 Returns `null` if the given argument could not be converted to a string.
1021 
1022 #### 6.42. `unshift(arr, v1, ...)`
1023 
1024 Add the given values to the beginning of the array passed as first argument.
1025 Returns the last value added to the array.
1026 
1027 #### 6.43. `values(obj)`
1028 
1029 Returns an array containing all values of the given object. Returns `null` if
1030 no object was passed.
1031 
1032 ```javascript
1033 values({ foo: true, bar: false });   // [true, false]
1034 ```
1035 
1036 #### 6.44. `printf(fmt, ...)`
1037 
1038 Formats the given arguments according to the given format string and outputs the
1039 result to stdout.
1040 
1041 Ucode supports a restricted subset of the formats allowed by the underlying
1042 libc's `printf()` implementation, namely it allows the `d`, `i`, `o`, `u`, `x`,
1043 `X`, `e`, `E`, `f`, `F`, `g`, `G`, `c` and `s` conversions.
1044 
1045 Additionally, an ucode specific `J` format is implemented, which causes the
1046 corresponding value to be formatted as JSON string. By prefixing the `J` format
1047 letter with a precision specifier, the resulting JSON output will be pretty
1048 printed. A precision of `0` will use tabs for indentation, any other positive
1049 precision will use that many spaces for indentation while a negative or omitted
1050 precision specifier will turn off pretty printing.
1051 
1052 Other format specifiers such as `n` or `z` are not accepted and returned
1053 verbatim. Format specifiers including `*` and `$` directives are rejected as
1054 well.
1055 
1056 ```javascript
1057 {%
1058   printf("Hello %s\n", "world");  // Hello world
1059   printf("%08x\n", 123);          // 0000007b
1060   printf("%c%c%c\n", 65, 98, 99); // Abc
1061   printf("%g\n", 10 / 3.0);       // 3.33333
1062   printf("%J", [1,2,3]);          // [ 1, 2, 3 ]
1063 
1064   printf("%.J", [1,2,3]);
1065   // [
1066   //         1,
1067   //         2,
1068   //         3
1069   // ]
1070 
1071   printf("%.2J", [1,2,3]);
1072   // [
1073   //   1,
1074   //   2,
1075   //   3
1076   // ]
1077 %}
1078 ```
1079 
1080 #### 6.45. `sprintf(fmt, ...)`
1081 
1082 Formats the given arguments according to the given format string and returns the
1083 resulting string.
1084 
1085 See `printf()` for details.
1086 
1087 #### 6.46. `match(str, /pattern/)`
1088 
1089 Match the given string against the regular expression pattern specified as
1090 second argument.
1091 
1092 If the passed regular expression uses the `g` flag, the return value will be an
1093 array of arrays describing all found occurences within the string.
1094 
1095 Without the `g` modifier, an array describing the first match is returned.
1096 Returns `null` if the pattern was not found within the given string.
1097 
1098 ```javascript
1099 match("foobarbaz", /b.(.)/)   // ["bar", "r"]
1100 match("foobarbaz", /b.(.)/g)  // [["bar", "r"], ["baz", "z"]]
1101 ```
1102 
1103 #### 6.47. `replace(str, /pattern/, replace[, limit])`
1104 
1105 Replace occurences of the specified pattern in the string passed as first
1106 argument. The pattern value may be either a regular expression or a plain
1107 string. The replace value may be a function which is invoked for each found
1108 pattern or any other value which is converted into a plain string and used as
1109 replacement.
1110 
1111 When an optional limit is specified, substitutions are performed only that
1112 many times.
1113 
1114 If the pattern is a regular expression and not using the `g` flag, then only the
1115 first occurence in the string is replaced, if the `g` flag is used or if the
1116 pattern is not a regular expression, all occurrences are replaced.
1117 
1118 If the replace value is a callback function, it is invoked with the found
1119 substring as first and any capture group values as subsequent parameters.
1120 
1121 If the replace value is a string, the following special substrings are
1122 substituted before it is inserted into the result:
1123 
1124  - `$$` - replaced by a literal `$`
1125  - ``$` `` - replaced by the text before the match
1126  - `$'` - replaced by the text after the match
1127  - `$&` - replaced by the matched substring
1128  - `$1`..`$9` - replaced by the value of the corresponding capture group, if the capture group is not defined, it is not substituted
1129 
1130 ```javascript
1131 replace("barfoobaz", /(f)(o+)/g, "[$$|$`|$&|$'|$1|$2|$3]")  // bar[$|bar|foo|baz|f|oo|$3]baz
1132 replace("barfoobaz", /(f)(o+)/g, uc)                        // barFOObaz
1133 replace("barfoobaz", "a", "X")                              // bXrfoobXz
1134 replace("barfoobaz", /(.)(.)(.)/g, function(m, c1, c2, c3) {
1135     return c3 + c2 + c1;
1136 })                                                          // raboofzab
1137 replace("aaaaa", "a", "x", 3)                               // xxxaa
1138 replace("foo bar baz", /[ao]/g, "x", 3)                     // fxx bxr baz
1139 ```
1140 
1141 #### 6.48. `json(str)`
1142 
1143 Parse the given string as JSON and return the resulting value. Throws an
1144 exception on parse errors, trailing garbage or premature EOF.
1145 
1146 ```javascript
1147 json('{"a":true, "b":123}')   // { "a": true, "b": 123 }
1148 json('[1,2,')                 // Throws exception
1149 ```
1150 
1151 #### 6.49. `include(path[, scope])`
1152 
1153 Evaluate and include the file at the given path and optionally override the
1154 execution scope with the given scope object.
1155 
1156 By default, the file is executed within the same scope as the calling
1157 `include()` but by passing an object as second argument, it is possible to
1158 extend the scope available to the included file. This is useful to supply
1159 additional properties as global variables to the included code.
1160 
1161 To sandbox included code, that is giving it only access to explicitely
1162 provided properties, the `proto()` function can be used to create a scope
1163 object with an empty prototype. See the examples below for details.
1164 
1165 If the given path argument is not absolute, it is interpreted relative to the
1166 directory of the current template file, that is the file that is invoking the
1167 `include()` function.
1168 
1169 If the ucode interpreter executes program code from stdin, the given path is
1170 interpreted relative to the current working directory of the process.
1171 
1172 ```javascript
1173 // Load and execute "foo.uc" immediately
1174 include("./foo.uc")
1175 
1176 // Execute the "supplemental.ucode" in an extended scope and make the "foo" and
1177 // "bar" properties available as global variables
1178 include("./supplemental.uc", {
1179   foo: true,
1180   bar: 123
1181 })
1182 
1183 // Execute the "untrusted.ucode" in a sandboxed scope and make the "foo" and
1184 // "bar" variables as well as the "print" function available to it. By assigning
1185 // an empty prototype object to the scope, included code has no access to
1186 // other global values anymore
1187 include("./untrusted.uc", proto({
1188   foo: true,
1189   bar: 123,
1190   print: print
1191 }, {}))
1192 ```
1193 
1194 #### 6.50. `warn(x, ...)`
1195 
1196 Print any of the given values to stderr. Arrays and objects are converted to
1197 their JSON representation.
1198 
1199 Returns the amount of bytes printed.
1200 
1201 #### 6.51. `system(command, timeout)`
1202 
1203 Executes the given command, waits for completion and returns the resulting
1204 exit code.
1205 
1206 The command argument may be either a string, in which case it is passed to
1207 `/bin/sh -c`, or an array, which is directly converted into an `execv()`
1208 argument vector.
1209 
1210 If the program terminated normally, a positive integer holding the programs
1211 `exit()` code is returned. If the program was terminated by an uncatched
1212 signal, a negative signal number is returned, e.g. `-9` when the program was
1213 terminated by `SIGKILL`.
1214 
1215 If the optional timeout argument is specified, the program is terminated by
1216 `SIGKILL` after that many milliseconds when it didn't complete within the timeout.
1217 
1218 Omitting the timeout argument, or passing `0` disables the command timeout.
1219 
1220 ```javascript
1221 // Execute through `/bin/sh`
1222 system("echo 'Hello world' && exit 3");    // prints "Hello world" to stdout and returns 3
1223 
1224 // Execute argument vector
1225 system(["/usr/bin/date", "+%s"]);          // prints the UNIX timestamp to stdout and returns 0
1226 
1227 // Apply a timeout
1228 system("sleep 3 && echo 'Success'", 1000); // returns -9
1229 ```
1230 
1231 #### 6.52. `trace(level)`
1232 
1233 Enables or disables VM opcode tracing. When invoked with a positive non-zero
1234 level, opcode tracing is enabled and debug information is printed to stderr
1235 as the program is executed.
1236 
1237 Invoking `trace()` with zero as argument will turn off opcode tracing.
1238 
1239 Right now, any positive non-zero value will enable tracing while future
1240 implementation might provide different different verbosity levels or treat
1241 the level argument as bit mask to enable or disable individual debug
1242 elements.
1243 
1244 #### 6.53. `proto(val[, proto])`
1245 
1246 Get or set the prototype of the array or object value `val`.
1247 
1248 When invoked without a second argument, the function returns the current
1249 prototype of the value in `val` or `null` if there is no prototype or if
1250 the given value is neither an object, nor an array.
1251 
1252 When invoked with a second prototype argument, the given `proto` value is
1253 set as prototype on the array or object in `val`.
1254 
1255 Throws an exception if the given prototype value is not an object.
1256 
1257 #### 6.54. `sleep(milliseconds)`
1258 
1259 Pause execution for the given amount of milliseconds. Returns `false` if
1260 an invalid value was passed, otherwise `true`.
1261 
1262 #### 6.55. `assert(cond[, message])`
1263 
1264 Raise an exception with the given `message` parameter if the value in `cond`
1265 is not truish. When `message` is omitted, the default value is `Assertion failed`.
1266 
1267 #### 6.56. `render(path_or_func[, scope_or_fnarg1 [, fnarg2 [, ...]]])`
1268 
1269 When invoked with a string value as first argument, the function acts like
1270 like `include()` but captures the output of the included file as string and
1271 returns the captured contents. The second argument is treated as scope. See
1272 `include()` for details on scoping.
1273 
1274 When invoked with a function value as first argument, `render()` calls the
1275 given function and passes all subsequent arguments to it. Any output
1276 (through print(), template text instructions and the like) produced by the
1277 called function is captured and returned as string. The return value of the
1278 called function is discarded.
1279 
1280 #### 6.57. `regexp(source[, flags])`
1281 
1282 Construct a regular expression instance from the given `source` pattern string
1283 and any flags optionally specified by the `flags` argument.
1284 
1285 Throws a type error exception if `flags` is not a string or if the string in
1286 `flags` contains unrecognized regular expression flag characters.
1287 
1288 Throws a syntax error when the pattern in `source` cannot be compiled into a
1289 valid regular expression by the underlying C runtimes `regcomp(3)` function.
1290 
1291 Returns the compiled regular expression value.
1292 
1293 ```javascript
1294 regexp('foo.*bar', 'is');   // equivalent to /foo.*bar/is
1295 regexp('foo.*bar', 'x');    // throws "Type error: Unrecognized flag character 'x'"
1296 regexp('foo.*(');           // throws "Syntax error: Unmatched ( or \("
1297 ```
1298 
1299 #### 6.58. `wildcard(subject, pattern[, nocase])`
1300 
1301 Match the given subject against the supplied wildcard (file glob) pattern.
1302 
1303 If a truish value is supplied as 3rd argument, case insensitive matching is
1304 performed. If a non-string value is supplied as subject, it is converted into
1305 a string before being matched.
1306 
1307 Returns `true` when the subject matches the pattern or `false` when not.
1308 
1309 #### 6.59. `sourcepath([depth [, dironly]])`
1310 
1311 Determine the path of the source file currently being executed by ucode.
1312 
1313 The optional `depth` parameter allows walking up the call stack to determine
1314 the path of the parent sources including or requiring the current source file.
1315 If unspecified, the `depth` defaults to `0`, that is the currently executed
1316 file.
1317 
1318 If a truish value is passed in `dironly`, only the directory portion of the
1319 source file path is returned.
1320 
1321 If the ucode interpreter executes code from stdin or a code fragment passed
1322 via `-s` switch, the function returns `null` since there is no associated
1323 file path.
1324 
1325 If `depth` exceeds the size of the call stack, the function returns `null`
1326 as well.
1327 
1328 #### 6.60. `min([val1 [, val2 [, ...]]])`
1329 
1330 Return the smallest value among all parameters passed to the function.
1331 The function does a `val1 < val2` comparison internally, which means that
1332 the same value coercion rules as for relational operators apply. If both
1333 strings and numbers are passed to `min()`, then any string values will be
1334 effectively ignored since both `1 < "abc"` and `1 > "abc"` comparisons
1335 yield false results.
1336 
1337 ```javascript
1338 min(5, 2.1, 3, "abc", 0.3);   // 0.3
1339 min(1, "abc");                // 1
1340 min("1", "abc");              // "1"
1341 min("def", "abc", "ghi");     // "abc"
1342 min(true, false);             // false
1343 ```
1344 
1345 #### 6.61. `max([val1 [, val2 [, ...]]])`
1346 
1347 Return the largest value among all parameters passed to the function.
1348 The function does a `val1 > val2` comparison internally, which means that
1349 the same value coercion rules as for relational operators apply. If both
1350 strings and numbers are passed to `min()`, then any string values will be
1351 effectively ignored since both `1 < "abc"` and `1 > "abc"` comparisons
1352 yield false results.
1353 
1354 ```javascript
1355 max(5, 2.1, 3, "abc", 0.3);   // 5
1356 max(1, "abc");                // 1 (!)
1357 max("1", "abc");              // "abc"
1358 max("def", "abc", "ghi");     // "ghi"
1359 max(true, false);             // true
1360 ```
1361 
1362 #### 6.62. `b64dec(str)`
1363 
1364 Decodes the given base64 encoded string and returns the decoded result, any
1365 whitespace in the input string is ignored.
1366 
1367 If non-whitespace, non-base64 characters are encountered, if invalid padding
1368 or trailing garbage is found, the function returns `null`.
1369 
1370 If a non-string argument is given, the function returns `null`.
1371 
1372 ```javascript
1373 b64dec("VGhpcyBpcyBhIHRlc3Q=");   // "This is a test"
1374 b64dec(123);                      // null
1375 b64dec("XXX");                    // null
1376 ```
1377 
1378 #### 6.63. `b64enc(str)`
1379 
1380 Encodes the given string into base64 and returns the resulting encoded
1381 string.
1382 
1383 If a non-string argument is given, the function returns `null`.
1384 
1385 ```javascript
1386 b64enc("This is a test");         // "VGhpcyBpcyBhIHRlc3Q="
1387 b64enc(123);                      // null
1388 ```
1389 
1390 #### 6.64. `uniq(array)`
1391 
1392 Returns a new array containing all unique values of the given input
1393 array. The order is preserved, that is subsequent duplicate values
1394 are simply skipped.
1395 
1396 If a non-array argument is given, the function returns `null`.
1397 
1398 ```javascript
1399 uniq([ 1, true, "foo", 2, true, "bar", "foo" ]); // [ 1, true, "foo", 2, "bar" ]
1400 uniq("test");                                    // null
1401 ```
1402 
1403 #### 6.65. `localtime([epoch])`
1404 
1405 Return the given epoch timestamp (or now, if omitted) as a dictionary
1406 containing broken-down date and time information according to the local
1407 system timezone.
1408 
1409 The resulting dictionary contains the following fields:
1410 
1411  - `sec`    Seconds (0-60)
1412  - `min`    Minutes (0-59)
1413  - `hour`   Hours (0-23)
1414  - `mday`   Day of month (1-31)
1415  - `mon`    Month (1-12)
1416  - `year`   Year (>= 1900)
1417  - `wday`   Day of the week (1-7, Sunday = 7)
1418  - `yday`   Day of the year (1-366, Jan 1st = 1)
1419  - `isdst`  Daylight saving time in effect (yes = 1)
1420 
1421 Note that in contrast to the underlying `localtime(3)` C library function,
1422 the values for `mon`, `wday` and `yday` are 1-based and the `year` is
1423 1900-based.
1424 
1425 ```javascript
1426 localtime(1647953502);
1427 // {
1428 //         "sec": 42,
1429 //         "min": 51,
1430 //         "hour": 13,
1431 //         "mday": 22,
1432 //         "mon": 3,
1433 //         "year": 2022,
1434 //         "wday": 2,
1435 //         "yday": 81,
1436 //         "isdst": 0
1437 // }
1438 ```
1439 
1440 #### 6.66. `gmtime([epoch])`
1441 
1442 Like `localtime()` but interpreting the given epoch value as UTC time.
1443 
1444 See `localtime()` for details on the return value.
1445 
1446 #### 6.67. `timelocal(datetimespec)`
1447 
1448 Performs the inverse operation of `localtime()` by taking a broken-down
1449 date and time dictionary and transforming it into an epoch value according
1450 to the local system timezone.
1451 
1452 The `wday` and `yday` fields of the given date time specification are
1453 ignored. Field values outside of their valid range are internally normalized,
1454 e.g. October 40th is interpreted as November 9th.
1455 
1456 Returns the resulting epoch value or null if the input date time dictionary
1457 was invalid or if the date time specification cannot be represented as
1458 epoch value.
1459 
1460 ```javascript
1461 timelocal({ "sec": 42, "min": 51, "hour": 13, "mday": 22, "mon": 3, "year": 2022, "isdst": 0 })
1462 // 1647953502
1463 ```
1464 
1465 #### 6.68. `timegm(datetimespec)`
1466 
1467 Like `timelocal()` but interpreting the given date time specification as
1468 UTC time.
1469 
1470 See `timelocal()` for details.
1471 
1472 #### 6.69. `clock([monotonic])`
1473 
1474 Reads the current second and microsecond value of the system clock.
1475 
1476 By default, the realtime clock is queried which might skew forwards
1477 or backwards due to NTP changes, system sleep modes etc.
1478 
1479 If a truish value is passed as argument, the monotonic system clock
1480 is queried instead, which will return the monotonically increasing
1481 time since some arbitrary point in the past (usually the system boot
1482 time).
1483 
1484 Returns a two element array containing the full seconds as first and
1485 the nanosecond fraction as second element.
1486 
1487 Returns `null` if a monotonic clock value is requested and the system
1488 does not implement this clock type.
1489 
1490 ```javascript
1491 clock();        // [ 1647954926, 798269464 ]
1492 clock(true);    // [ 474751, 527959975 ]
1493 ```
1494 
1495 #### 6.70. `hexdec(hexstring[, skipchars])`
1496 
1497 The `hexdec()` function decodes the given hexadecimal digit string into
1498 a byte string, optionally skipping specified characters.
1499 
1500 If the characters to skip are not specified, a default of `" \t\n"` is
1501 used.
1502 
1503 Returns null if the input string contains invalid characters or an uneven
1504 amount of hex digits.
1505 
1506 Returns the decoded byte string on success.
1507 
1508 ```javascript
1509 hexdec("48656c6c6f20776f726c64210a");  // "Hello world!\n"
1510 hexdec("44:55:66:77:33:44", ":");      // "DUfw3D"
1511 ```
1512 
1513 #### 6.71. `hexenc(val)`
1514 
1515 The `hexenc()` function encodes the given byte string into a hexadecimal
1516 digit string, converting the input value to a string if needed.
1517 
1518 Returns the encoded hexadecimal digit string.
1519 
1520 ```javascript
1521 hexenc("Hello world!\n");   // "48656c6c6f20776f726c64210a"
1522 ```
1523 
1524 #### 6.72. `gc([operation[, argument]])`
1525 
1526 The `gc()` function allows interaction with the mark and sweep garbage
1527 collector of the running ucode virtual machine.
1528 
1529 Depending on the given `operation` string argument, the meaning of
1530 `argument` and the function return value differs.
1531 
1532 The following operations are defined:
1533 
1534  - `collect` - Perform a complete garbage collection cycle, returns `true`.
1535  - `start` - (Re-)start periodic garbage collection, `argument` is an optional
1536              integer in the range 1..65535 specifying the interval. Defaults
1537              to `1000` if omitted. Returns `true` if the periodic GC was
1538              previously stopped and is now started or if the interval changed.
1539              Returns `false` otherwise.
1540  - `stop` - Stop periodic garbage collection. Returns `true` if the periodic GC
1541             was previously started and is now stopped, `false` otherwise.
1542  - `count` - Count the amount of active complex object references in the VM
1543              context, returns the counted amount.
1544 
1545 If the `operation` argument is omitted, the default is `collect`.
1546 
1547 Returns `null` if a non-string `operation` value is given.
1548 
1549 #### 6.73. `loadstring(code[, options])`
1550 
1551 Compiles the given code string into a ucode program and returns the resulting
1552 program entry function. The optinal `options` dictionary allows overriding
1553 parse and compile options.
1554 
1555 If a non-string `code` argument is given, it is implicitly converted to a
1556 string value first.
1557 
1558 If `options` is omitted or a non-object value, the compile options of the
1559 running ucode program are reused.
1560 
1561 The following keys in the `options` dictionary are recognized:
1562 
1563 | Key                   | Type  | Description                                              |
1564 |-----------------------|-------|----------------------------------------------------------|
1565 | `lstrip_blocks`       | bool  | Strip leading whitespace before statement template blocks|
1566 | `trim_blocks`         | bool  | Strip newline after statement template blocks            |
1567 | `strict_declarations` | bool  | Treat access to undefined variables as fatal error       |
1568 | `raw_mode`            | bool  | Compile source in script mode, don't treat it as template|
1569 | `module_search_path`  | array | Override compile time module search path                 |
1570 | `force_dynlink_list`  | array | List of module names to treat as dynamic extensions      |
1571 
1572 Unrecognized keys are ignored, unspecified options default to those of the
1573 running program.
1574 
1575 Returns the compiled program entry function.
1576 
1577 Throws an exception on compilation errors.
1578 
1579 ```javascript
1580 let fn1 = loadstring("Hello, {{ name }}", { raw_mode: false });
1581 
1582 global.name = "Alice";
1583 fn1(); // prints `Hello, Alice`
1584 
1585 
1586 let fn2 = loadstring("return 1 + 2;", { raw_mode: true });
1587 fn2(); // 3
1588 ```
1589 
1590 #### 6.74. `loadfile(path[, options])`
1591 
1592 Compiles the given file into a ucode program and returns the resulting program
1593 entry function.
1594 
1595 See `loadfile()` for details.
1596 
1597 Returns the compiled program entry function.
1598 
1599 Throws an exception on compilation or file i/o errors.
1600 
1601 ```javascript
1602 loadfile("./templates/example.uc");  // function main() { ... }
1603 ```
1604 
1605 #### 6.75. `call(fn[, ctx[, scope[, arg1[, ...]]]])`
1606 
1607 Calls the given function value with a modified environment. The given `ctx`
1608 argument is used as `this` context for the invoked function and the given
1609 `scope` value as global environment. Any further arguments are passed to the
1610 invoked function as-is.
1611 
1612 When `ctx` is omitted or `null`, the function will get invoked with `this`
1613 being `null`.
1614 
1615 When `scope` is omitted or `null`, the function will get executed with the
1616 current global environment of the running program. When `scope` is set to a
1617 dictionary, the dictionary is used as global function environment.
1618 
1619 When the `scope` dictionary has no prototype, the current global environment
1620 will be set as prototype, means the scope will inherit from it. When a scope
1621 prototype is set, it is kept. This allows passing an isolated (sandboxed)
1622 function scope without access to the global environment.
1623 
1624 Any further argument is forwarded as-is to the invoked function as function
1625 call argument.
1626 
1627 Returns `null` if the given function value `fn` is not callable.
1628 
1629 Returns the return value of the invoked function in all other cases.
1630 
1631 Forwards exceptions thrown by the invoked function.
1632 
1633 ```javascript
1634 // Override this context
1635 call(function() { printf("%J\n", this) });            // null
1636 call(function() { printf("%J\n", this) }, null);      // null
1637 call(function() { printf("%J\n", this) }, { x: 1 });  // { "x": 1 }
1638 call(function() { printf("%J\n", this) }, { x: 2 });  // { "x": 2 }
1639 
1640 // Run with default scope
1641 global.a = 1;
1642 call(function() { printf("%J\n", a) });                  // 1
1643 
1644 // Override scope, inherit from current global scope (implicit)
1645 call(function() { printf("%J\n", a) }, null, { a: 2 });  // 2
1646 
1647 // Override scope, inherit from current global scope (explicit)
1648 call(function() { printf("%J\n", a) }, null,
1649         proto({ a: 2 }, global));                        // 2
1650 
1651 // Override scope, don't inherit (pass `printf()` but not `a`)
1652 call(function() { printf("%J\n", a) }, null,
1653         proto({}, { printf }));                          // null
1654 
1655 // Forward arguments
1656 x = call((x, y, z) => x * y * z, null, null, 2, 3, 4);   // x = 24
1657 ```

This page was automatically generated by LXR 0.3.1.  •  OpenWrt