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