novac 2.0.1 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +1574 -597
- package/bin/novac +468 -171
- package/bin/nvc +522 -0
- package/bin/nvml +78 -17
- package/demo.nv +0 -0
- package/demo_builtins.nv +0 -0
- package/demo_http.nv +0 -0
- package/examples/bf.nv +69 -0
- package/examples/math.nv +21 -0
- package/kits/birdAPI/kitdef.js +954 -0
- package/kits/kitRNG/kitdef.js +740 -0
- package/kits/kitSSH/kitdef.js +1272 -0
- package/kits/kitadb/kitdef.js +606 -0
- package/kits/kitai/kitdef.js +2185 -0
- package/kits/kitansi/kitdef.js +1402 -0
- package/kits/kitcanvas/kitdef.js +914 -0
- package/kits/kitclippy/kitdef.js +925 -0
- package/kits/kitformat/kitdef.js +1485 -0
- package/kits/kitgps/kitdef.js +1862 -0
- package/kits/kitlibproc/kitdef.js +3 -2
- package/kits/kitmatrix/ex.js +19 -0
- package/kits/kitmatrix/kitdef.js +960 -0
- package/kits/kitmorse/kitdef.js +229 -0
- package/kits/kitmpatch/kitdef.js +906 -0
- package/kits/kitnet/kitdef.js +1401 -0
- package/kits/kitnovacweb/README.md +1416 -143
- package/kits/kitnovacweb/kitdef.js +92 -2
- package/kits/kitnovacweb/nvml/executor.js +578 -176
- package/kits/kitnovacweb/nvml/index.js +2 -2
- package/kits/kitnovacweb/nvml/lexer.js +72 -69
- package/kits/kitnovacweb/nvml/parser.js +328 -159
- package/kits/kitnovacweb/nvml/renderer.js +770 -270
- package/kits/kitparse/kitdef.js +1688 -0
- package/kits/kitproto/kitdef.js +613 -0
- package/kits/kitqr/kitdef.js +637 -0
- package/kits/kitregex++/kitdef.js +1353 -0
- package/kits/kitrequire/kitdef.js +1599 -0
- package/kits/kitx11/kitdef.js +1 -0
- package/kits/kitx11/kitx11.js +2472 -0
- package/kits/kitx11/kitx11_conn.js +948 -0
- package/kits/kitx11/kitx11_worker.js +121 -0
- package/kits/libtea/kitdef.js +2691 -0
- package/kits/libterm/ex.js +285 -0
- package/kits/libterm/kitdef.js +1927 -0
- package/novac/LICENSE +21 -0
- package/novac/README.md +1823 -0
- package/novac/bin/novac +950 -0
- package/novac/bin/nvc +522 -0
- package/novac/bin/nvml +542 -0
- package/novac/demo.nv +245 -0
- package/novac/demo_builtins.nv +209 -0
- package/novac/demo_http.nv +62 -0
- package/novac/examples/bf.nv +69 -0
- package/novac/examples/math.nv +21 -0
- package/novac/kits/kitai/kitdef.js +2185 -0
- package/novac/kits/kitansi/kitdef.js +1402 -0
- package/novac/kits/kitformat/kitdef.js +1485 -0
- package/novac/kits/kitgps/kitdef.js +1862 -0
- package/novac/kits/kitlibfs/kitdef.js +231 -0
- package/{examples/example-project/nova_modules → novac/kits}/kitlibproc/kitdef.js +3 -2
- package/novac/kits/kitmatrix/ex.js +19 -0
- package/novac/kits/kitmatrix/kitdef.js +960 -0
- package/novac/kits/kitmpatch/kitdef.js +906 -0
- package/novac/kits/kitnovacweb/README.md +1572 -0
- package/novac/kits/kitnovacweb/demo.nv +12 -0
- package/novac/kits/kitnovacweb/demo.nvml +71 -0
- package/novac/kits/kitnovacweb/index.nova +12 -0
- package/novac/kits/kitnovacweb/kitdef.js +692 -0
- package/novac/kits/kitnovacweb/nova.kit.json +8 -0
- package/novac/kits/kitnovacweb/nvml/executor.js +739 -0
- package/novac/kits/kitnovacweb/nvml/index.js +67 -0
- package/novac/kits/kitnovacweb/nvml/lexer.js +263 -0
- package/novac/kits/kitnovacweb/nvml/parser.js +508 -0
- package/novac/kits/kitnovacweb/nvml/renderer.js +924 -0
- package/novac/kits/kitparse/kitdef.js +1688 -0
- package/novac/kits/kitregex++/kitdef.js +1353 -0
- package/novac/kits/kitrequire/kitdef.js +1599 -0
- package/novac/kits/kitx11/kitdef.js +1 -0
- package/novac/kits/kitx11/kitx11.js +2472 -0
- package/novac/kits/kitx11/kitx11_conn.js +948 -0
- package/novac/kits/kitx11/kitx11_worker.js +121 -0
- package/novac/kits/libtea/tf.js +2691 -0
- package/novac/kits/libterm/ex.js +285 -0
- package/novac/kits/libterm/kitdef.js +1927 -0
- package/novac/node_modules/chalk/license +9 -0
- package/novac/node_modules/chalk/package.json +83 -0
- package/novac/node_modules/chalk/readme.md +297 -0
- package/novac/node_modules/chalk/source/index.d.ts +325 -0
- package/novac/node_modules/chalk/source/index.js +225 -0
- package/novac/node_modules/chalk/source/utilities.js +33 -0
- package/novac/node_modules/chalk/source/vendor/ansi-styles/index.d.ts +236 -0
- package/novac/node_modules/chalk/source/vendor/ansi-styles/index.js +223 -0
- package/novac/node_modules/chalk/source/vendor/supports-color/browser.d.ts +1 -0
- package/novac/node_modules/chalk/source/vendor/supports-color/browser.js +34 -0
- package/novac/node_modules/chalk/source/vendor/supports-color/index.d.ts +55 -0
- package/novac/node_modules/chalk/source/vendor/supports-color/index.js +190 -0
- package/novac/node_modules/commander/LICENSE +22 -0
- package/novac/node_modules/commander/Readme.md +1176 -0
- package/novac/node_modules/commander/esm.mjs +16 -0
- package/novac/node_modules/commander/index.js +24 -0
- package/novac/node_modules/commander/lib/argument.js +150 -0
- package/novac/node_modules/commander/lib/command.js +2777 -0
- package/novac/node_modules/commander/lib/error.js +39 -0
- package/novac/node_modules/commander/lib/help.js +747 -0
- package/novac/node_modules/commander/lib/option.js +380 -0
- package/novac/node_modules/commander/lib/suggestSimilar.js +101 -0
- package/novac/node_modules/commander/package-support.json +19 -0
- package/novac/node_modules/commander/package.json +82 -0
- package/novac/node_modules/commander/typings/esm.d.mts +3 -0
- package/novac/node_modules/commander/typings/index.d.ts +1113 -0
- package/novac/node_modules/node-addon-api/LICENSE.md +9 -0
- package/novac/node_modules/node-addon-api/README.md +95 -0
- package/novac/node_modules/node-addon-api/common.gypi +21 -0
- package/novac/node_modules/node-addon-api/except.gypi +25 -0
- package/novac/node_modules/node-addon-api/index.js +14 -0
- package/novac/node_modules/node-addon-api/napi-inl.deprecated.h +186 -0
- package/novac/node_modules/node-addon-api/napi-inl.h +7165 -0
- package/novac/node_modules/node-addon-api/napi.h +3364 -0
- package/novac/node_modules/node-addon-api/node_addon_api.gyp +42 -0
- package/novac/node_modules/node-addon-api/node_api.gyp +9 -0
- package/novac/node_modules/node-addon-api/noexcept.gypi +26 -0
- package/novac/node_modules/node-addon-api/package-support.json +21 -0
- package/novac/node_modules/node-addon-api/package.json +480 -0
- package/novac/node_modules/node-addon-api/tools/README.md +73 -0
- package/novac/node_modules/node-addon-api/tools/check-napi.js +99 -0
- package/novac/node_modules/node-addon-api/tools/clang-format.js +71 -0
- package/novac/node_modules/node-addon-api/tools/conversion.js +301 -0
- package/novac/node_modules/serialize-javascript/LICENSE +27 -0
- package/novac/node_modules/serialize-javascript/README.md +149 -0
- package/novac/node_modules/serialize-javascript/index.js +297 -0
- package/novac/node_modules/serialize-javascript/package.json +33 -0
- package/novac/package.json +27 -0
- package/novac/scripts/update-bin.js +24 -0
- package/novac/src/core/bstd.js +1035 -0
- package/novac/src/core/config.js +155 -0
- package/novac/src/core/describe.js +187 -0
- package/novac/src/core/emitter.js +499 -0
- package/novac/src/core/error.js +86 -0
- package/novac/src/core/executor.js +5606 -0
- package/novac/src/core/formatter.js +686 -0
- package/novac/src/core/lexer.js +1026 -0
- package/novac/src/core/nova_builtins.js +717 -0
- package/novac/src/core/nova_thread_worker.js +166 -0
- package/novac/src/core/parser.js +2181 -0
- package/novac/src/core/types.js +112 -0
- package/novac/src/index.js +28 -0
- package/novac/src/runtime/stdlib.js +244 -0
- package/package.json +6 -3
- package/scripts/update-bin.js +0 -0
- package/src/core/bstd.js +838 -362
- package/src/core/executor.js +2578 -170
- package/src/core/lexer.js +502 -54
- package/src/core/nova_builtins.js +21 -3
- package/src/core/parser.js +413 -72
- package/src/core/types.js +30 -2
- package/src/index.js +0 -0
- package/examples/example-project/README.md +0 -3
- package/examples/example-project/src/main.nova +0 -3
- package/src/core/environment.js +0 -0
- /package/{examples/example-project/bin/example-project.nv → novac/node_modules/node-addon-api/nothing.c} +0 -0
package/README.md
CHANGED
|
@@ -1,846 +1,1823 @@
|
|
|
1
|
-
#
|
|
1
|
+
# novac Language Reference
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
novac is a dynamic, expressive scripting language with a JavaScript-style syntax, a rich infix operator set, built-in event system, HTTP primitives, a Nova Classic layer, and a comprehensive standard library. Files use the `.nv` or `.nova` extension and are run with the `novac` CLI.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
##
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
| `switch` / `case` / `default` | JS-style with fall-through |
|
|
35
|
-
| Ternary | `cond ? a : b` |
|
|
36
|
-
| Bitwise ops | `& \| ^ ~ << >> >>>` |
|
|
37
|
-
| Range operator | `1..10` |
|
|
38
|
-
| Pipe operator | `x \|> fn` |
|
|
39
|
-
| Hex literals | `0xFF` |
|
|
40
|
-
| Binary literals | `0b1010` |
|
|
41
|
-
| Numeric separators | `1_000_000` |
|
|
42
|
-
| Scientific notation | `1.5e3` |
|
|
43
|
-
| Block comment | `/* ... */` |
|
|
44
|
-
| Optional catch | `try { } catch { }` (no binding required) |
|
|
45
|
-
| Computed property keys | `{ [expr]: val }` |
|
|
46
|
-
| Getter/setter methods | `get prop() { }` / `set prop(v) { }` |
|
|
47
|
-
| `new` expression | `new ClassName()` |
|
|
48
|
-
| Keyword operators | `and or not` |
|
|
49
|
-
| `as` cast | `x as int` |
|
|
50
|
-
|
|
51
|
-
### Added — Nova-unique features
|
|
52
|
-
| Feature | Syntax |
|
|
53
|
-
|---|---|
|
|
54
|
-
| `each` loop | `each x, i of arr { }` |
|
|
55
|
-
| `match` expression | pattern matching, no fall-through |
|
|
56
|
-
| `match` guards | `when val where cond { }` |
|
|
57
|
-
| `emit` / `on` events | `emit "event", val` / `on "event"(v) { }` |
|
|
58
|
-
| `where` block | scoped bindings `where(x=1, y=2) { }` |
|
|
59
|
-
| `assert` | `assert cond, "message"` |
|
|
60
|
-
| `give` | early-return alias |
|
|
61
|
-
| `unless` | `unless (cond) { }` |
|
|
62
|
-
| `until` | `until (cond) { }` |
|
|
63
|
-
| `repeat` | `repeat (n) { }` |
|
|
64
|
-
| **Custom types** | `type`, `struct`, `interface`, `enum`, `trait`, `impl` |
|
|
65
|
-
| Preprocessor | `#define`, `#ifdef`, `#ifndef`, `#endif`, `#register`, `#inject` |
|
|
66
|
-
| Pointer syntax | `let *p = val`, `*p = newVal` |
|
|
67
|
-
| Currency units | `5 k` → 5000, `3 m` → 3000000 |
|
|
68
|
-
| `__identifier indentifier__` | double-underscore identifier escaping that work just like strings but give out indents|
|
|
69
|
-
| Runtime type registry | `typecheck(v, "int")`, `typeOf(v)`, `satisfies(v, "IFace")` |
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
1. [Comments](#comments)
|
|
10
|
+
2. [Preprocessor Directives](#preprocessor-directives)
|
|
11
|
+
3. [Literals & Values](#literals--values)
|
|
12
|
+
4. [Variables & Smart Modifiers](#variables--smart-modifiers)
|
|
13
|
+
5. [Types](#types)
|
|
14
|
+
6. [Operators](#operators)
|
|
15
|
+
7. [Strings & F-Strings](#strings--f-strings)
|
|
16
|
+
8. [Control Flow](#control-flow)
|
|
17
|
+
9. [Functions](#functions)
|
|
18
|
+
10. [Classes](#classes)
|
|
19
|
+
11. [Pattern Matching](#pattern-matching)
|
|
20
|
+
12. [Events](#events)
|
|
21
|
+
13. [Error Handling](#error-handling)
|
|
22
|
+
14. [Modules & Namespaces](#modules--namespaces)
|
|
23
|
+
15. [HTTP & Networking](#http--networking)
|
|
24
|
+
16. [Nova Classic Features](#nova-classic-features)
|
|
25
|
+
17. [Built-in Global Objects](#built-in-global-objects)
|
|
26
|
+
18. [Built-in Class Objects](#built-in-class-objects)
|
|
27
|
+
19. [Standard Library (std)](#standard-library-std)
|
|
28
|
+
20. [Standard Built-ins (bstd / import_builtin)](#standard-builtins-bstd--import_builtin)
|
|
29
|
+
21. [Array Methods](#array-methods)
|
|
30
|
+
22. [Object Methods](#object-methods)
|
|
31
|
+
23. [String Methods](#string-methods)
|
|
32
|
+
24. [Type System & Casting](#type-system--casting)
|
|
33
|
+
25. [Threads](#threads)
|
|
70
34
|
|
|
71
35
|
---
|
|
72
36
|
|
|
73
|
-
##
|
|
37
|
+
## Comments
|
|
74
38
|
|
|
75
|
-
### `type` — type aliases
|
|
76
39
|
```nova
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
40
|
+
// single-line comment
|
|
41
|
+
/! also a single-line comment
|
|
42
|
+
/* multi-line block comment */
|
|
43
|
+
|
|
44
|
+
/?/ core.print("executed at lex time") // executable comment — runs during lexing
|
|
81
45
|
```
|
|
82
46
|
|
|
83
|
-
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Preprocessor Directives
|
|
50
|
+
|
|
84
51
|
```nova
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
52
|
+
#define NAME value // substitution macro (NAME replaced everywhere in source)
|
|
53
|
+
#define FLAG // valueless flag (for ifdef/ifndef)
|
|
54
|
+
#undef NAME // remove a macro
|
|
55
|
+
#ifdef FLAG // include following block only if FLAG is defined
|
|
56
|
+
#ifndef FLAG // include following block only if FLAG is NOT defined
|
|
57
|
+
#endif // close an ifdef/ifndef block
|
|
58
|
+
#register operator NAME {"precedence":N, "isUnary":bool}
|
|
59
|
+
#inject <json-token> // inject a raw token into the token stream
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Literals & Values
|
|
65
|
+
|
|
66
|
+
### Numbers
|
|
67
|
+
|
|
68
|
+
| Form | Example | Notes |
|
|
69
|
+
|------|---------|-------|
|
|
70
|
+
| Decimal | `42`, `3.14` | Standard |
|
|
71
|
+
| Separator | `1_000_000` | Underscores ignored |
|
|
72
|
+
| Hex | `0xFF` | Case insensitive |
|
|
73
|
+
| Binary | `0b1010` | Case insensitive |
|
|
74
|
+
| Custom base | `0r16FF` | `0r<base><digits>`, base 2–36 |
|
|
75
|
+
| Holland/scale | `0hbillion`, `0hmega` | Named SI / large-number literals |
|
|
76
|
+
| BigInt | `42n` | Suffix `n` |
|
|
77
|
+
| Scientific | `1e6`, `2.5E-3` | Standard scientific |
|
|
78
|
+
| Short suffix | `10k`, `2m`, `1b`, `4t` | k=1e3, m=1e6, b=1e9, t=1e12 |
|
|
79
|
+
|
|
80
|
+
**Holland scale literals** — `0h` prefix:
|
|
81
|
+
|
|
82
|
+
| Name | Value | Name | Value |
|
|
83
|
+
|------|-------|------|-------|
|
|
84
|
+
| `kilo` | 1e3 | `milli` | 1e-3 |
|
|
85
|
+
| `mega` | 1e6 | `micro` | 1e-6 |
|
|
86
|
+
| `giga` | 1e9 | `nano` | 1e-9 |
|
|
87
|
+
| `tera` | 1e12 | `pico` | 1e-12 |
|
|
88
|
+
| `million` | 1e6 | `femto` | 1e-15 |
|
|
89
|
+
| `billion` | 1e9 | `atto` | 1e-18 |
|
|
90
|
+
| `trillion` | 1e12 | `googol` | 1e100 |
|
|
91
|
+
| `quadrillion` | 1e15 | | |
|
|
92
|
+
| `quintillion` | 1e18 | | |
|
|
93
|
+
|
|
94
|
+
### Special Literals
|
|
95
|
+
|
|
96
|
+
| Token | Value |
|
|
97
|
+
|-------|-------|
|
|
98
|
+
| `true` | boolean true |
|
|
99
|
+
| `false` | boolean false |
|
|
100
|
+
| `null` | null |
|
|
101
|
+
| `nstr` | `""` (empty string) |
|
|
102
|
+
| `nfunc` | A function that returns null |
|
|
103
|
+
|
|
104
|
+
### URL Literals
|
|
105
|
+
|
|
106
|
+
Tokens beginning with a recognized scheme are URL literals:
|
|
107
|
+
|
|
108
|
+
```nova
|
|
109
|
+
let url = https://api.example.com/users
|
|
110
|
+
let local = localhost:3000
|
|
111
|
+
// Recognized: http, https, ftp, ws, wss, content, localhost:<port>
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Arrays
|
|
115
|
+
|
|
116
|
+
```nova
|
|
117
|
+
let arr = [1, 2, 3]
|
|
118
|
+
let spread = [...arr, 4, 5]
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Objects
|
|
122
|
+
|
|
123
|
+
```nova
|
|
124
|
+
let obj = { x: 1, 'y': 2 }
|
|
125
|
+
let method = { greet() { give "hi"; } }
|
|
126
|
+
let overload = {
|
|
127
|
+
[op]: {
|
|
128
|
+
unary: { '~': () => 17 }
|
|
129
|
+
binary: { '+': (a) => a*10 }
|
|
130
|
+
}
|
|
88
131
|
}
|
|
132
|
+
core.print(~obj + obj); // ~obj becomes 17, now 17 + obj becomes 17*10 which is 170.
|
|
133
|
+
let computed = { ["key" + idx]: value }
|
|
134
|
+
let withSpread = { ...obj, z: 3 }
|
|
135
|
+
let getset = {
|
|
136
|
+
get prop() { give this._val; },
|
|
137
|
+
set prop(v) { this._val = v; }
|
|
138
|
+
}
|
|
139
|
+
let presence = { active? true } // boolean-constrained property: must be true or false
|
|
140
|
+
```
|
|
89
141
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Variables & Smart Modifiers
|
|
145
|
+
|
|
146
|
+
```nova
|
|
147
|
+
var x = 10 // mutable, function-scoped
|
|
148
|
+
let y = 20 // mutable, block-scoped
|
|
149
|
+
const Z = 30 // immutable binding/
|
|
150
|
+
// special __...__ identifiers:
|
|
151
|
+
let __my cool variable++-__ = 19; // when novac sees __, it collects everything until __ as the var name and gives an identifier token type, so you can even name a variable __26__ and the token with be { type: 'IDENTIFIER', value: '26' }
|
|
94
152
|
```
|
|
95
153
|
|
|
96
|
-
###
|
|
154
|
+
### Destructuring
|
|
155
|
+
|
|
97
156
|
```nova
|
|
98
|
-
|
|
99
|
-
|
|
157
|
+
let { a, b } = obj
|
|
158
|
+
let { a: renamed, b: other = "default" } = obj
|
|
159
|
+
let [first, second] = arr
|
|
160
|
+
let [head, ...tail] = arr
|
|
161
|
+
```
|
|
100
162
|
|
|
101
|
-
|
|
102
|
-
core.print(d.__variant__); // North
|
|
163
|
+
### Smart Variable Modifiers
|
|
103
164
|
|
|
104
|
-
|
|
105
|
-
|
|
165
|
+
Placed between the variable name and `=`:
|
|
166
|
+
|
|
167
|
+
| Modifier | Effect |
|
|
168
|
+
|----------|--------|
|
|
169
|
+
| `frozen` | Throws on any reassignment after first set |
|
|
170
|
+
| `lazy` | Expression evaluated only on first read |
|
|
171
|
+
| `tracked` | `console.log`s every assignment change |
|
|
172
|
+
| `nonull` | Throws if assigned `null` or `undefined` |
|
|
173
|
+
| `once` | Can only be set once; further assigns silently ignored |
|
|
174
|
+
| `setter <fn>` | Calls `fn(newVal, oldVal)` on every assignment; if fn returns non-undefined, that becomes the stored value |
|
|
175
|
+
| `getter <fn>` | Calls `fn()` on every read |
|
|
176
|
+
| `as fnum [min, max]` | Clamps to float range on every assign |
|
|
177
|
+
| `as fint [min, max]` | Clamps to integer range (`Math.trunc`) on every assign |
|
|
178
|
+
|
|
179
|
+
```nova
|
|
180
|
+
let x frozen = 5
|
|
181
|
+
let y lazy = computeHeavy()
|
|
182
|
+
let z tracked = 0
|
|
183
|
+
let n nonull = getValue()
|
|
184
|
+
let once_val once = initialize()
|
|
185
|
+
let watched setter mySetFn = 0
|
|
186
|
+
let computed getter myGetFn = 0
|
|
187
|
+
let clamped as fnum [0.0, 1.0] = 0.5
|
|
188
|
+
let bounded as fint [0, 255] = 128
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Links and $-notations
|
|
192
|
+
```nova
|
|
193
|
+
let obj = { test: { example: 29 } };
|
|
194
|
+
let link2example = link(obj.test.example); // link is not a function, its a special keyword function
|
|
195
|
+
link2example = 3; // example is also set
|
|
196
|
+
obj.test.example; // 3
|
|
197
|
+
obj.test.example = 2;
|
|
198
|
+
link2example; // 2
|
|
199
|
+
// you can also directly set a link call:
|
|
200
|
+
link(obj.test.example) = 1; // works
|
|
201
|
+
// nest links:
|
|
202
|
+
link(link2example) = 3; // now obj.test.example is also 3
|
|
106
203
|
```
|
|
107
204
|
|
|
108
|
-
### `interface` — structural contracts
|
|
109
205
|
```nova
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
206
|
+
// $ notation:
|
|
207
|
+
// when used as a normal call:
|
|
208
|
+
$29; // noop, just 29
|
|
209
|
+
${a: 6 + 3}; // noop again, just the object
|
|
210
|
+
// real magic in $ assingments:
|
|
211
|
+
$"hi" = 29; // sets variable hi
|
|
212
|
+
$26 = 1; // set variable 26, even tho you can't just read from a var directly called 26, you can still use __26__ to read (novac trims __...__ and just leaves an ident with value ...)
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Type Annotation
|
|
216
|
+
|
|
217
|
+
```nova
|
|
218
|
+
let count: int = 0
|
|
219
|
+
let name: string = "Nova"
|
|
220
|
+
func add(a: int, b: int): int => { give a + b }
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Pointer Declaration & Dereference
|
|
224
|
+
|
|
225
|
+
```nova
|
|
226
|
+
var *ptr = someValue
|
|
227
|
+
let result = *ptr // dereference
|
|
228
|
+
*ptr = newValue // assign through pointer
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## Types
|
|
234
|
+
|
|
235
|
+
### Type Alias
|
|
236
|
+
|
|
237
|
+
```nova
|
|
238
|
+
type ID = string
|
|
239
|
+
type Status = "active" | "inactive" | "pending"
|
|
240
|
+
type Point = { x: int, y: int }
|
|
241
|
+
type Result<T> = T | null
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Struct
|
|
245
|
+
|
|
246
|
+
```nova
|
|
247
|
+
struct Vec2 {
|
|
248
|
+
x: int = 0,
|
|
249
|
+
y: int = 0
|
|
113
250
|
}
|
|
251
|
+
let v = Vec2({ x: 3, y: 4 })
|
|
252
|
+
v.x // 3
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Interface
|
|
114
256
|
|
|
115
|
-
|
|
116
|
-
|
|
257
|
+
```nova
|
|
258
|
+
interface Serializable {
|
|
259
|
+
serialize(): string
|
|
260
|
+
deserialize(data: string): bool
|
|
261
|
+
name?: string // optional member
|
|
262
|
+
}
|
|
263
|
+
interface Extended extends Serializable, Printable { }
|
|
117
264
|
```
|
|
118
265
|
|
|
119
|
-
###
|
|
266
|
+
### Enum
|
|
267
|
+
|
|
120
268
|
```nova
|
|
121
|
-
|
|
122
|
-
|
|
269
|
+
enum Status { Active, Inactive, Pending }
|
|
270
|
+
enum Shape {
|
|
271
|
+
Circle(int),
|
|
272
|
+
Rect(int, int),
|
|
273
|
+
Point = 0
|
|
123
274
|
}
|
|
275
|
+
let s = Status.Active
|
|
276
|
+
s.__variant__ // "Active"
|
|
277
|
+
s.__enum_type__ // "Status"
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Trait & Impl
|
|
124
281
|
|
|
125
|
-
|
|
282
|
+
```nova
|
|
283
|
+
trait Drawable {
|
|
284
|
+
draw(ctx) { }
|
|
285
|
+
}
|
|
286
|
+
impl Drawable of Circle {
|
|
287
|
+
draw(ctx) { ctx.circle(this.x, this.y, this.r); }
|
|
288
|
+
}
|
|
289
|
+
// Also: impl Drawable for Circle { }
|
|
126
290
|
```
|
|
127
291
|
|
|
292
|
+
### Type Expressions
|
|
293
|
+
|
|
294
|
+
```nova
|
|
295
|
+
string | null // union
|
|
296
|
+
int & Serializable // intersection
|
|
297
|
+
string[] // array type
|
|
298
|
+
{ name: string, age?: int } // inline shape type
|
|
299
|
+
Map<string, int> // generic
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
## Operators
|
|
305
|
+
|
|
306
|
+
### Arithmetic
|
|
307
|
+
|
|
308
|
+
| Op | Meaning |
|
|
309
|
+
|----|---------|
|
|
310
|
+
| `+` `-` `*` `/` `%` | Standard arithmetic |
|
|
311
|
+
| `**` | Exponentiation (right-associative) |
|
|
312
|
+
| `++` `--` | Increment / decrement (prefix or postfix) |
|
|
313
|
+
|
|
314
|
+
### Assignment
|
|
315
|
+
|
|
316
|
+
| Op | Meaning |
|
|
317
|
+
|----|---------|
|
|
318
|
+
| `=` | Assign |
|
|
319
|
+
| `+=` `-=` `*=` `/=` `%=` `**=` | Compound assign |
|
|
320
|
+
| `&&=` | Logical-AND assign |
|
|
321
|
+
| `\|\|=` | Assign if current is null/undefined |
|
|
322
|
+
| `??=` | Nullish-coalesce assign |
|
|
323
|
+
|
|
324
|
+
### Comparison
|
|
325
|
+
|
|
326
|
+
| Op | Meaning |
|
|
327
|
+
|----|---------|
|
|
328
|
+
| `==` `!=` | Loose equality |
|
|
329
|
+
| `===` `!==` | Strict equality |
|
|
330
|
+
| `<` `>` `<=` `>=` | Relational |
|
|
331
|
+
| `is` | Strict equality alias |
|
|
332
|
+
| `isnt` | Non-identity alias |
|
|
333
|
+
| `equals` | `===` alias |
|
|
334
|
+
| `equals_ignore` | Case-insensitive string equality |
|
|
335
|
+
| `cmp` | `localeCompare` — returns -1/0/1 |
|
|
336
|
+
|
|
337
|
+
### Logical
|
|
338
|
+
|
|
339
|
+
| Op | Meaning |
|
|
340
|
+
|----|---------|
|
|
341
|
+
| `&&` / `and` | Logical AND |
|
|
342
|
+
| `\|\|` / `or` | Logical OR |
|
|
343
|
+
| `!` / `not` | Logical NOT (unary) |
|
|
344
|
+
| `??` | Nullish coalesce |
|
|
345
|
+
| `xor` | Exclusive OR |
|
|
346
|
+
| `nand` | NOT AND |
|
|
347
|
+
| `nor` | NOT OR |
|
|
348
|
+
| `xnor` | Exclusive NOR |
|
|
349
|
+
|
|
350
|
+
### Bitwise
|
|
351
|
+
|
|
352
|
+
| Op | Meaning |
|
|
353
|
+
|----|---------|
|
|
354
|
+
| `&` `\|` `^` `~` | Bitwise AND / OR / XOR / NOT |
|
|
355
|
+
| `<<` `>>` `>>>` | Left / right / unsigned right shift |
|
|
356
|
+
|
|
357
|
+
### Type & Predicate
|
|
358
|
+
|
|
359
|
+
| Op | Meaning |
|
|
360
|
+
|----|---------|
|
|
361
|
+
| `typeof` | Returns type string (unary) |
|
|
362
|
+
| `instanceof` | Instance check |
|
|
363
|
+
| `in` | Membership / range containment |
|
|
364
|
+
| `istypeof` | `typeOf(left) === right` |
|
|
365
|
+
| `matches` | Regex test of left string against right |
|
|
366
|
+
| `between` | `left > arr[0] && left < arr[1]` |
|
|
367
|
+
|
|
368
|
+
### Special / Flow
|
|
369
|
+
|
|
370
|
+
| Op | Meaning |
|
|
371
|
+
|----|---------|
|
|
372
|
+
| `\|>` | Pipe: `x \|> f` → `f(x)` |
|
|
373
|
+
| `=>` | Arrow function body |
|
|
374
|
+
| `..` | Inclusive range: `1..10` → `NovaRange(1,10)` |
|
|
375
|
+
| `...` (unary) | Spread / rest |
|
|
376
|
+
| `...` (binary) | Exclusive range: `1...10` → array `[1..9]` |
|
|
377
|
+
| `?.` | Optional chain — null if left is null |
|
|
378
|
+
| `?` | Ternary start |
|
|
379
|
+
| `::` | Namespace / property access |
|
|
380
|
+
| `>>` | Pipe-right: `val >> fn` → `fn(val)`; also used in `compose` / `engage` |
|
|
381
|
+
| `delete` | Delete variable, property, or subscript |
|
|
382
|
+
| `void` | Evaluate and return undefined |
|
|
383
|
+
| `#` | Size of right operand (array/object/string length) |
|
|
384
|
+
|
|
385
|
+
### Array / Collection Infix
|
|
386
|
+
|
|
387
|
+
| Op | Meaning |
|
|
388
|
+
|----|---------|
|
|
389
|
+
| `intersect` | Elements in both arrays |
|
|
390
|
+
| `union` | Deduplicated merge |
|
|
391
|
+
| `diff_arr` | Elements in left not in right |
|
|
392
|
+
| `zip` | `[[a0,b0],[a1,b1],...]` |
|
|
393
|
+
| `extend` | Merge objects / concatenate arrays |
|
|
394
|
+
| `concat` | Concatenate |
|
|
395
|
+
| `index` | `arr index 2` → element at 2 |
|
|
396
|
+
| `step` | `0..10 step 2` → `[0,2,4,6,8,10]` |
|
|
397
|
+
|
|
398
|
+
### Numeric Infix
|
|
399
|
+
|
|
400
|
+
| Op | Meaning |
|
|
401
|
+
|----|---------|
|
|
402
|
+
| `avg` | `(a + b) / 2` |
|
|
403
|
+
| `diff` | `Math.abs(a - b)` |
|
|
404
|
+
| `ratio` | `a / b` |
|
|
405
|
+
| `mult_of` | `a % b === 0` |
|
|
406
|
+
| `gcd` | Greatest common divisor |
|
|
407
|
+
| `lcm` | Least common multiple |
|
|
408
|
+
| `pow` | Alias for `**` |
|
|
409
|
+
| `bigger` / `smaller` | `a > b` / `a < b` aliases |
|
|
410
|
+
|
|
411
|
+
### String Infix
|
|
412
|
+
|
|
413
|
+
| Op | Meaning |
|
|
414
|
+
|----|---------|
|
|
415
|
+
| `pad_start` | `.padStart(right, ' ')` |
|
|
416
|
+
| `pad_end` | `.padEnd(right, ' ')` |
|
|
417
|
+
|
|
418
|
+
### Operator Precedence (highest → lowest)
|
|
419
|
+
|
|
420
|
+
| Prec | Operators |
|
|
421
|
+
|------|-----------|
|
|
422
|
+
| 15 | `++` `--` (postfix), `?.`, `::`, `#:`, `$:`, `index` |
|
|
423
|
+
| 14 | Unary: `!` `~` `-` `+` `*` `...` `not` `typeof` `void` `delete` |
|
|
424
|
+
| 13 | `**` `pow` (right-assoc) |
|
|
425
|
+
| 12 | `*` `/` `%` `ratio` `mult_of` `gcd` `lcm` |
|
|
426
|
+
| 11 | `+` `-` `avg` `diff` `pad_start` `pad_end` `concat` |
|
|
427
|
+
| 10 | `>>` `<<` `>>>` `..` `step` `zip` |
|
|
428
|
+
| 9 | `<` `>` `<=` `>=` `bigger` `smaller` |
|
|
429
|
+
| 8 | `==` `!=` `===` `!==` `is` `isnt` `equals` `equals_ignore` `cmp` `istypeof` `matches` `instanceof` `in` |
|
|
430
|
+
| 7 | `&` `intersect` `diff_arr` |
|
|
431
|
+
| 6 | `^` |
|
|
432
|
+
| 5 | `\|` `union` `extend` |
|
|
433
|
+
| 4 | `&&` `and` `nand` |
|
|
434
|
+
| 3 | `??` `xor` `xnor` |
|
|
435
|
+
| 2 | `\|\|` `or` `nor` |
|
|
436
|
+
| 0 | `=` `+=` `-=` `*=` `/=` `%=` `**=` `&&=` `\|\|=` `??=` `=>` `\|>` |
|
|
437
|
+
|
|
128
438
|
---
|
|
129
439
|
|
|
130
|
-
##
|
|
440
|
+
## Strings & F-Strings
|
|
131
441
|
|
|
132
|
-
### Variables
|
|
133
442
|
```nova
|
|
134
|
-
let
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
443
|
+
let a = "hello"
|
|
444
|
+
let b = 'world'
|
|
445
|
+
// Escape sequences: \n \t \r \\ \' \"...etc
|
|
446
|
+
|
|
447
|
+
// F-strings: f"..." with {} interpolation — any expression allowed
|
|
448
|
+
let msg = f"\color{blue}Hello {name}!\reset"
|
|
449
|
+
let math = f"2^10 = {2 ** 10}"
|
|
450
|
+
let complex = f"items: {arr.map(x => x * 2).join(', ')}"
|
|
139
451
|
```
|
|
140
452
|
|
|
141
|
-
|
|
453
|
+
---
|
|
454
|
+
|
|
455
|
+
## Control Flow
|
|
456
|
+
|
|
457
|
+
### If / Else
|
|
458
|
+
|
|
142
459
|
```nova
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
460
|
+
if (cond) { } else if (other) { } else { }
|
|
461
|
+
|
|
462
|
+
let x = a > b ? a : b // ternary
|
|
463
|
+
let y = value if condition else alt // postfix if-expression
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
### Unless / Until / Repeat
|
|
146
467
|
|
|
147
|
-
|
|
148
|
-
|
|
468
|
+
```nova
|
|
469
|
+
unless (cond) { } // runs when cond is false
|
|
470
|
+
until (cond) { } // runs while cond is false
|
|
471
|
+
repeat (n) { } // runs exactly n times
|
|
149
472
|
```
|
|
150
473
|
|
|
151
|
-
###
|
|
474
|
+
### While / Do-While
|
|
475
|
+
|
|
152
476
|
```nova
|
|
153
|
-
|
|
154
|
-
|
|
477
|
+
while (cond) { }
|
|
478
|
+
do { } while (cond)
|
|
155
479
|
```
|
|
156
480
|
|
|
157
|
-
###
|
|
481
|
+
### For
|
|
482
|
+
|
|
158
483
|
```nova
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
until (done) { ... }
|
|
163
|
-
do { ... } while (cond);
|
|
164
|
-
repeat (5) { ... }
|
|
165
|
-
for (let i = 0; i < 10; i++) { ... }
|
|
166
|
-
for (let x of array) { ... }
|
|
167
|
-
for (let k in obj) { ... }
|
|
168
|
-
each val, idx of array { ... }
|
|
484
|
+
for (let i = 0; i < 10; i++) { }
|
|
485
|
+
for (let item of array) { }
|
|
486
|
+
for (let key in object) { }
|
|
169
487
|
```
|
|
170
488
|
|
|
171
|
-
###
|
|
489
|
+
### Each
|
|
490
|
+
|
|
172
491
|
```nova
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
when 1, 2, 3 { core.print("small"); }
|
|
176
|
-
when 4..10 { core.print("range"); } // range pattern!
|
|
177
|
-
when x where x > 100 { core.print("big"); } // guarded
|
|
178
|
-
default { core.print("other"); }
|
|
179
|
-
}
|
|
492
|
+
each item of array { }
|
|
493
|
+
each item, index of array { }
|
|
180
494
|
```
|
|
181
495
|
|
|
182
|
-
###
|
|
496
|
+
### Switch / Case
|
|
497
|
+
|
|
183
498
|
```nova
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
get label() { give this.sound; }
|
|
499
|
+
switch (value) {
|
|
500
|
+
case 1: core.print("one"); break;
|
|
501
|
+
default: core.print("other"); break;
|
|
188
502
|
}
|
|
503
|
+
```
|
|
189
504
|
|
|
190
|
-
|
|
191
|
-
sound: "Woof"
|
|
192
|
-
}
|
|
505
|
+
### Match
|
|
193
506
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
507
|
+
```nova
|
|
508
|
+
match (value) {
|
|
509
|
+
when 1 { }
|
|
510
|
+
when 2, 3 { } // comma = multi-pattern
|
|
511
|
+
when 1..10 { } // range
|
|
512
|
+
when "ok" where cond { } // with guard
|
|
513
|
+
default { }
|
|
514
|
+
}
|
|
197
515
|
```
|
|
198
516
|
|
|
199
|
-
###
|
|
517
|
+
### Loop Control
|
|
518
|
+
|
|
519
|
+
| Keyword | Effect |
|
|
520
|
+
|---------|--------|
|
|
521
|
+
| `break` | Exit loop |
|
|
522
|
+
| `continue` | Next iteration |
|
|
523
|
+
| `skip` | Alias for `continue` (parsed as `skip`, no-op in execute) |
|
|
524
|
+
| `goback` | Throw `{ __return: scope.__return }` — return from function |
|
|
525
|
+
| `end` | Throw `{ __return: undefined }` — terminate scope |
|
|
526
|
+
|
|
527
|
+
### Guard
|
|
528
|
+
|
|
200
529
|
```nova
|
|
201
|
-
|
|
202
|
-
|
|
530
|
+
guard (cond) {
|
|
531
|
+
// body runs only when cond is TRUE (passes through)
|
|
532
|
+
} else {
|
|
533
|
+
// runs when cond is FALSE
|
|
534
|
+
}
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
### When
|
|
203
538
|
|
|
204
|
-
|
|
539
|
+
```nova
|
|
540
|
+
when cond do { } // runs body once if cond is truthy
|
|
541
|
+
when cond then { } // same
|
|
205
542
|
```
|
|
206
543
|
|
|
207
|
-
###
|
|
544
|
+
### Where (scoped bindings)
|
|
545
|
+
|
|
208
546
|
```nova
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
547
|
+
where (base = 100, rate = 0.15) {
|
|
548
|
+
let tax = base * rate
|
|
549
|
+
}
|
|
212
550
|
```
|
|
213
551
|
|
|
214
|
-
###
|
|
552
|
+
### With
|
|
553
|
+
|
|
215
554
|
```nova
|
|
216
|
-
|
|
217
|
-
|
|
555
|
+
with (object) {
|
|
556
|
+
// object properties brought into scope
|
|
557
|
+
}
|
|
558
|
+
with option featureFlag {
|
|
559
|
+
// body runs with flag set; removed after block
|
|
218
560
|
}
|
|
561
|
+
```
|
|
219
562
|
|
|
220
|
-
|
|
563
|
+
### Loop (Classic iteration)
|
|
564
|
+
|
|
565
|
+
```nova
|
|
566
|
+
loop item in iterable { }
|
|
221
567
|
```
|
|
222
568
|
|
|
223
|
-
###
|
|
569
|
+
### Foreach (Classic key-value)
|
|
570
|
+
|
|
224
571
|
```nova
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
}
|
|
228
|
-
// x, y not accessible here
|
|
572
|
+
foreach(collection)(key, value) { }
|
|
573
|
+
foreach(collection)(key, value, length) { } // third var = total length
|
|
229
574
|
```
|
|
230
575
|
|
|
231
|
-
###
|
|
576
|
+
### Wait (sync sleep)
|
|
577
|
+
|
|
232
578
|
```nova
|
|
233
|
-
|
|
234
|
-
|
|
579
|
+
wait(1000) // blocks for 1000ms (Atomics.wait, fallback: child process)
|
|
580
|
+
```
|
|
235
581
|
|
|
236
|
-
|
|
237
|
-
core.print("debug mode");
|
|
238
|
-
#endif
|
|
582
|
+
### Time Block
|
|
239
583
|
|
|
240
|
-
|
|
584
|
+
```nova
|
|
585
|
+
time {
|
|
586
|
+
// times this block; prints elapsed ms on completion
|
|
587
|
+
}
|
|
241
588
|
```
|
|
242
589
|
|
|
243
590
|
---
|
|
244
591
|
|
|
245
|
-
##
|
|
592
|
+
## Functions
|
|
246
593
|
|
|
247
|
-
|
|
248
|
-
`flat`, `flatMap`, `sort`, `reverse`, `slice`, `splice`,
|
|
249
|
-
`indexOf`, `includes`, `join`, `push`, `pop`, `shift`, `unshift`,
|
|
250
|
-
`concat`, `fill`, `forEach`, `keys`, `values`, `entries`, `at`
|
|
594
|
+
### Named Functions
|
|
251
595
|
|
|
252
|
-
|
|
596
|
+
```nova
|
|
597
|
+
func add(a, b) => {
|
|
598
|
+
give a + b
|
|
599
|
+
}
|
|
600
|
+
function greet(name) {
|
|
601
|
+
return f"Hello {name}"
|
|
602
|
+
}
|
|
603
|
+
```
|
|
253
604
|
|
|
254
|
-
|
|
255
|
-
`int`, `console`, `Date`, `json`, `Promise`, `fn`, `range`, `error`
|
|
605
|
+
### Function Modifiers
|
|
256
606
|
|
|
257
|
-
|
|
607
|
+
Modifiers come **after** `func`/`function` and **before** the function name. Multiple modifiers can be chained in any order.
|
|
608
|
+
|
|
609
|
+
| Modifier | Effect |
|
|
610
|
+
|----------|--------|
|
|
611
|
+
| `async` | Marks async; `await` blocks synchronously via `SharedArrayBuffer` |
|
|
612
|
+
| `Strict` | Throws if argument count doesn't match exactly |
|
|
613
|
+
| `once` | Body only runs once; later calls return the first result |
|
|
614
|
+
| `memo` | Results memoized by `JSON.stringify(args)` key |
|
|
615
|
+
| `generator` | Returns an iterator; `yield` inside collects values |
|
|
616
|
+
| `timeout <expr>` | Throws if function exceeds `expr` ms |
|
|
617
|
+
| `defer <stmt>` | Executes `stmt` when function returns (in `finally`) |
|
|
618
|
+
|
|
619
|
+
```nova
|
|
620
|
+
func async load(url) => { }
|
|
621
|
+
func Strict strict(a, b) => { }
|
|
622
|
+
func once init() => { }
|
|
623
|
+
func memo fib(n) => { }
|
|
624
|
+
func generator counter() => { }
|
|
625
|
+
func async memo cachedFetch(url) => { }
|
|
626
|
+
func timeout 5000 riskyOp() => { }
|
|
627
|
+
func defer cleanup() riskyOp() => { }
|
|
628
|
+
|
|
629
|
+
// function keyword works identically
|
|
630
|
+
function async load(url) { }
|
|
631
|
+
function Strict strict(a, b) { }
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
in objects, you can have a [expr] quick access method that runs on
|
|
635
|
+
obj.(...args)
|
|
636
|
+
example:
|
|
637
|
+
```nova
|
|
638
|
+
let obj = { [expr]: (a, b) => return a + b }
|
|
639
|
+
core.print(obj.(1,5)); // 6
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
### Generator Iterator API
|
|
643
|
+
|
|
644
|
+
| Method | Description |
|
|
645
|
+
|--------|-------------|
|
|
646
|
+
| `.next()` | `{ value, done }` |
|
|
647
|
+
| `.last()` | Step back one |
|
|
648
|
+
| `.current()` | Peek without advancing |
|
|
649
|
+
| `.seek(n)` | Jump to index n |
|
|
650
|
+
| `.setIndex(n)` | Set position |
|
|
651
|
+
| `.currentIndex()` | Current index |
|
|
652
|
+
| `.length()` | Total collected values |
|
|
653
|
+
| `.at(n)` | Value at index n |
|
|
654
|
+
| `[Symbol.iterator]` | Makes it iterable in `for-of` |
|
|
655
|
+
|
|
656
|
+
### Return / Give / Goback
|
|
258
657
|
|
|
259
|
-
|
|
658
|
+
```nova
|
|
659
|
+
return value // sets __return, does NOT terminate
|
|
660
|
+
give value // alias — same as return, but terminates the function by throwing
|
|
661
|
+
goback // throws { __return: scope.__return }
|
|
662
|
+
yield value // collects into generator's output array
|
|
663
|
+
```
|
|
260
664
|
|
|
261
|
-
|
|
665
|
+
### Arrow Functions
|
|
262
666
|
|
|
263
|
-
|
|
667
|
+
```nova
|
|
668
|
+
let double = x => x * 2
|
|
669
|
+
let add = (a, b) => a + b
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
### Rest & Default Parameters
|
|
673
|
+
|
|
674
|
+
```nova
|
|
675
|
+
func sum(...nums) => { give nums.reduce((a, b) => a + b, 0) }
|
|
676
|
+
func greet(name = "World") => { }
|
|
677
|
+
```
|
|
264
678
|
|
|
679
|
+
### Block functions:
|
|
680
|
+
these auto call on reference, and use the returned value
|
|
265
681
|
```nova
|
|
266
|
-
|
|
267
|
-
core.print(
|
|
682
|
+
block coolBlock { core.print(8); return 8; }
|
|
683
|
+
core.print(coolBlock); /* result:
|
|
684
|
+
8 //from inside coolBlock
|
|
685
|
+
8 //from core.print(coolBlock);
|
|
686
|
+
*/
|
|
687
|
+
// you can also just run the block using nova.runBlock('coolBlock')
|
|
268
688
|
```
|
|
269
689
|
|
|
270
|
-
###
|
|
690
|
+
### Run bounder:
|
|
691
|
+
```nova
|
|
692
|
+
// run CODE
|
|
693
|
+
// or
|
|
694
|
+
// run { ... }
|
|
695
|
+
// example:
|
|
696
|
+
core.print(run let x = 10); //10 because run uses last result if no return/give
|
|
697
|
+
core.print(x); // 10
|
|
698
|
+
core.print(run { let c = 8; return c; }); // 8
|
|
699
|
+
core.print(c); // 8
|
|
700
|
+
|
|
701
|
+
```
|
|
271
702
|
|
|
272
|
-
|
|
273
|
-
Optional `(body, headers)` args are passed as the request body and headers.
|
|
703
|
+
### Pipe Operator
|
|
274
704
|
|
|
275
705
|
```nova
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
core.print(todos.status); // 200
|
|
279
|
-
core.print(todos.ok); // true
|
|
280
|
-
core.print(todos.body.title);
|
|
706
|
+
let result = 5 |> double |> addOne
|
|
707
|
+
```
|
|
281
708
|
|
|
282
|
-
|
|
283
|
-
let created = post https://api.example.com/users({ name: "Alice", age: 30 });
|
|
709
|
+
---
|
|
284
710
|
|
|
285
|
-
|
|
286
|
-
let updated = put https://api.example.com/users/1({ name: "Bob" });
|
|
287
|
-
let patched = patch https://api.example.com/users/1({ age: 31 });
|
|
711
|
+
## Classes
|
|
288
712
|
|
|
289
|
-
|
|
290
|
-
|
|
713
|
+
```nova
|
|
714
|
+
class Animal {
|
|
715
|
+
name: "unknown"
|
|
716
|
+
speak() { core.print(f"{this.name} speaks") }
|
|
717
|
+
}
|
|
718
|
+
class Dog extends Animal {
|
|
719
|
+
breed: "mixed"
|
|
720
|
+
speak() { core.print(f"{this.name} barks") }
|
|
721
|
+
}
|
|
722
|
+
class Doc implements Serializable {
|
|
723
|
+
// must satisfy all non-optional interface members
|
|
724
|
+
}
|
|
725
|
+
```
|
|
726
|
+
|
|
727
|
+
### Getter / Setter
|
|
291
728
|
|
|
292
|
-
|
|
293
|
-
|
|
729
|
+
```nova
|
|
730
|
+
class Box {
|
|
731
|
+
_val: 0
|
|
732
|
+
get value() { give this._val; }
|
|
733
|
+
set value(v) { this._val = v; }
|
|
734
|
+
}
|
|
294
735
|
```
|
|
295
736
|
|
|
296
|
-
###
|
|
737
|
+
### Decorators
|
|
297
738
|
|
|
298
739
|
```nova
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
740
|
+
@logged
|
|
741
|
+
@deprecated("use newFn")
|
|
742
|
+
class OldClass {
|
|
743
|
+
@readonly
|
|
744
|
+
name: "old"
|
|
745
|
+
}
|
|
746
|
+
```
|
|
302
747
|
|
|
303
|
-
|
|
304
|
-
|
|
748
|
+
---
|
|
749
|
+
|
|
750
|
+
## Pattern Matching
|
|
305
751
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
}
|
|
752
|
+
```nova
|
|
753
|
+
match (value) {
|
|
754
|
+
when 90..100 { } // range — uses NovaRange.includes()
|
|
755
|
+
when "ok" { } // scalar — uses ==
|
|
756
|
+
when 1, 2, 3 { } // any of these — comma-separated
|
|
757
|
+
when x where x > 0 { } // with guard expression
|
|
758
|
+
default { }
|
|
759
|
+
}
|
|
312
760
|
```
|
|
313
761
|
|
|
314
|
-
|
|
762
|
+
---
|
|
763
|
+
|
|
764
|
+
## Events
|
|
765
|
+
|
|
315
766
|
```nova
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
767
|
+
emit "eventName"
|
|
768
|
+
emit "eventName", payload
|
|
769
|
+
|
|
770
|
+
on "eventName" (data) {
|
|
771
|
+
core.print(data)
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
// Internal: fires on every statement execution step
|
|
775
|
+
on "nv:tick" () { }
|
|
320
776
|
```
|
|
321
777
|
|
|
322
|
-
|
|
778
|
+
---
|
|
779
|
+
|
|
780
|
+
## Error Handling
|
|
323
781
|
|
|
324
782
|
```nova
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
}
|
|
783
|
+
try {
|
|
784
|
+
riskyOp()
|
|
785
|
+
} catch (err) {
|
|
786
|
+
core.print(f"caught: {err}")
|
|
787
|
+
} finally {
|
|
788
|
+
cleanup()
|
|
789
|
+
}
|
|
329
790
|
|
|
330
|
-
|
|
331
|
-
let body = req.body;
|
|
332
|
-
return { created: true, name: body.name };
|
|
333
|
-
}
|
|
791
|
+
try { riskyOp() } catch { } // no binding — catch without name
|
|
334
792
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
}
|
|
793
|
+
throw "plain string"
|
|
794
|
+
throw new Error("typed")
|
|
338
795
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
}
|
|
796
|
+
assert condition
|
|
797
|
+
assert condition, "failure message"
|
|
342
798
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
return { error: "Not found" };
|
|
346
|
-
}
|
|
799
|
+
expt "expectedOutput" from {
|
|
800
|
+
core.print("expectedOutput")
|
|
347
801
|
}
|
|
348
802
|
```
|
|
349
803
|
|
|
350
|
-
|
|
351
|
-
| Property | Description |
|
|
352
|
-
|---|---|
|
|
353
|
-
| `req.method` | HTTP method string |
|
|
354
|
-
| `req.url` | Full URL including query string |
|
|
355
|
-
| `req.path` | Pathname only |
|
|
356
|
-
| `req.params` | Object of `:param` captures |
|
|
357
|
-
| `req.query` | Object of `?key=value` pairs |
|
|
358
|
-
| `req.headers` | Request headers |
|
|
359
|
-
| `req.body` | Parsed JSON body |
|
|
804
|
+
---
|
|
360
805
|
|
|
361
|
-
|
|
362
|
-
| Method | Description |
|
|
363
|
-
|---|---|
|
|
364
|
-
| `res.status(code)` | Set status code (chainable) |
|
|
365
|
-
| `res.json(data)` | Send JSON response |
|
|
366
|
-
| `res.send(text)` | Send plain text |
|
|
806
|
+
## Modules & Namespaces
|
|
367
807
|
|
|
368
|
-
|
|
808
|
+
### Import
|
|
369
809
|
|
|
370
|
-
|
|
810
|
+
```nova
|
|
811
|
+
import "path/to/module"
|
|
812
|
+
import "path/to/module" as alias
|
|
813
|
+
import "path/to/module" as name1, name2
|
|
814
|
+
from "module" import func1, func2
|
|
815
|
+
import_builtin Air, Chalk, Input, Shema
|
|
816
|
+
```
|
|
817
|
+
|
|
818
|
+
### Export
|
|
819
|
+
|
|
820
|
+
```nova
|
|
821
|
+
export myValue
|
|
822
|
+
export { name = value, other = value2 }
|
|
823
|
+
default myMainExport
|
|
824
|
+
```
|
|
371
825
|
|
|
372
|
-
|
|
826
|
+
### Namespace
|
|
373
827
|
|
|
374
828
|
```nova
|
|
375
|
-
|
|
376
|
-
|
|
829
|
+
namespace Math {
|
|
830
|
+
func add(a, b) => { give a + b }
|
|
377
831
|
}
|
|
832
|
+
Math::add(1, 2)
|
|
833
|
+
using namespace Math // bring all members into scope
|
|
834
|
+
```
|
|
835
|
+
|
|
836
|
+
### Using / Unuse
|
|
378
837
|
|
|
379
|
-
|
|
380
|
-
|
|
838
|
+
```nova
|
|
839
|
+
using featureFlag
|
|
840
|
+
using namespace MyNS
|
|
841
|
+
unuse featureFlag
|
|
381
842
|
```
|
|
382
843
|
|
|
383
|
-
###
|
|
844
|
+
### Environment Variable
|
|
384
845
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
3. **PowerShell** `Invoke-WebRequest` — Windows fallback
|
|
389
|
-
4. **Node.js built-in** `http`/`https` — universal last resort (always available)
|
|
846
|
+
```nova
|
|
847
|
+
env VAR_NAME // reads process.env.VAR_NAME; throws if undefined
|
|
848
|
+
```
|
|
390
849
|
|
|
391
850
|
---
|
|
392
851
|
|
|
393
|
-
##
|
|
852
|
+
## HTTP & Networking
|
|
394
853
|
|
|
854
|
+
### First-Class HTTP Verbs
|
|
395
855
|
|
|
396
|
-
```
|
|
397
|
-
|
|
398
|
-
novac
|
|
856
|
+
```nova
|
|
857
|
+
get https://api.example.com/users
|
|
858
|
+
post https://api.example.com/users({ name: "novac" })
|
|
859
|
+
put https://api.example.com/users/1({ name: "Updated" })
|
|
860
|
+
delete https://api.example.com/users/1()
|
|
861
|
+
patch https://api.example.com/users/1({ active: false })
|
|
862
|
+
head https://api.example.com/health
|
|
863
|
+
options https://api.example.com/
|
|
864
|
+
// Returns: { ok: bool, status: int, body: object|string, text: string }
|
|
865
|
+
```
|
|
866
|
+
|
|
867
|
+
**Sync fetch strategies (tried in order):** in-process local Nova server dispatch → curl → PowerShell (Windows) → Node child process.
|
|
399
868
|
|
|
400
|
-
|
|
401
|
-
novac repl
|
|
869
|
+
### Fetch
|
|
402
870
|
|
|
403
|
-
|
|
404
|
-
|
|
871
|
+
```nova
|
|
872
|
+
fetch(url)
|
|
873
|
+
fetch(url, { method: "POST", headers: { Authorization: "Bearer x" }, body: payload })
|
|
874
|
+
fetch(url, opts) => resultVar // statement form — assigns result
|
|
405
875
|
```
|
|
406
876
|
|
|
877
|
+
### Server Declaration
|
|
407
878
|
|
|
408
|
-
|
|
879
|
+
```nova
|
|
880
|
+
server(3000) {
|
|
881
|
+
get "/api/users" (req, res) {
|
|
882
|
+
res.json([])
|
|
883
|
+
}
|
|
884
|
+
post "/api/users" (req, res) {
|
|
885
|
+
res.json({ created: true, body: req.body })
|
|
886
|
+
}
|
|
887
|
+
delete "/api/users/:id" (req, res) {
|
|
888
|
+
res.json({ deleted: req.params.id })
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
// req: { method, url, path, headers, body, params, query }
|
|
892
|
+
// res: .status(code) .header(k,v) .json(data) .send(data)
|
|
893
|
+
// :param values also bound directly into route scope
|
|
894
|
+
// If res.json/send never called, route handler's return value is auto-sent
|
|
895
|
+
```
|
|
409
896
|
|
|
410
|
-
|
|
897
|
+
---
|
|
411
898
|
|
|
412
|
-
|
|
899
|
+
## @classic — Classic Compatibility Block
|
|
413
900
|
|
|
414
|
-
|
|
901
|
+
Classic novac keywords are **only valid inside an `@classic { }` block**. Outside of one they are plain identifiers and cause a parse error if used as statements. This keeps the core language surface area clean while preserving full backward compatibility for legacy code.
|
|
415
902
|
|
|
416
903
|
```nova
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
904
|
+
@classic {
|
|
905
|
+
// any classic keyword works in here
|
|
906
|
+
echo "hello"
|
|
907
|
+
keep port = 8080
|
|
908
|
+
gear(500) poll {
|
|
909
|
+
let data = fetch(https://api.example.com/data)
|
|
910
|
+
echo data.body
|
|
911
|
+
}
|
|
912
|
+
engage poll
|
|
420
913
|
}
|
|
421
914
|
```
|
|
422
915
|
|
|
423
|
-
|
|
916
|
+
If you use a Classic keyword outside `@classic`, the parser throws:
|
|
917
|
+
|
|
918
|
+
```
|
|
919
|
+
ClassicError: 'echo' is a Classic novac keyword and must be used inside an @classic { } block.
|
|
920
|
+
Wrap your legacy code: @classic { echo ... }
|
|
921
|
+
```
|
|
922
|
+
|
|
923
|
+
`@classic` blocks can appear anywhere a statement is valid — top-level, inside functions, inside `if` bodies, etc. They share the same scope as their surroundings.
|
|
424
924
|
|
|
425
925
|
```nova
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
926
|
+
func migrate() => {
|
|
927
|
+
@classic {
|
|
928
|
+
backup session = currentSession
|
|
929
|
+
temp session = "migration" => {
|
|
930
|
+
runMigration()
|
|
931
|
+
}
|
|
932
|
+
retrieve session
|
|
933
|
+
}
|
|
430
934
|
}
|
|
431
|
-
|
|
935
|
+
```
|
|
432
936
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
937
|
+
### Classic Keywords (only valid inside `@classic { }`)
|
|
938
|
+
|
|
939
|
+
**Output:**
|
|
940
|
+
|
|
941
|
+
| Keyword | Behavior |
|
|
942
|
+
|---------|----------|
|
|
943
|
+
| `echo value` | `process.stdout.write(String(value))` — no newline |
|
|
944
|
+
| `print(val, ...)` | Space-joined args + newline |
|
|
945
|
+
| `println(value)` | `process.stdout.write(value)` — no newline |
|
|
946
|
+
| `log(val, ...)` | `console.log(...args)` |
|
|
947
|
+
| `logln(value)` | `process.stdout.write(value)` |
|
|
948
|
+
| `warn "msg"` | `"Warning: msg\n"` |
|
|
949
|
+
| `info "msg"` | `"INFO: msg\n"` |
|
|
950
|
+
| `hello` | Prints `"Hello, !"` |
|
|
951
|
+
| `hello "a", "b"` | Prints `"Hello, a, and b!"` |
|
|
952
|
+
| `banner "text"` | Box-drawn ASCII banner |
|
|
953
|
+
|
|
954
|
+
**Scoped Binding:**
|
|
955
|
+
|
|
956
|
+
| Keyword | Behavior |
|
|
957
|
+
|---------|----------|
|
|
958
|
+
| `temp x = val => { }` | Override x for the block duration, then restore |
|
|
959
|
+
| `keep x = val` | Set x only if currently null/undefined; silent otherwise |
|
|
960
|
+
|
|
961
|
+
**Macros & Named Code:**
|
|
962
|
+
|
|
963
|
+
| Keyword | Behavior |
|
|
964
|
+
|---------|----------|
|
|
965
|
+
| `macro NAME = val` | Store value in `nova.macros` and scope |
|
|
966
|
+
| `snippet name { }` | Register named snippet; run with `nova.runSnippet("name")` |
|
|
967
|
+
| `defunc name(args) => { }` | Declare function (arrow-body style) |
|
|
968
|
+
| `lambda name = x => expr` | Declare arrow function |
|
|
969
|
+
| `compose name = f >> g` | Compose functions left-to-right: `g(f(x))` |
|
|
970
|
+
| `partial name = fn(arg)` | Partial application |
|
|
971
|
+
|
|
972
|
+
**Iteration:**
|
|
973
|
+
|
|
974
|
+
| Keyword | Behavior |
|
|
975
|
+
|---------|----------|
|
|
976
|
+
| `loop item in iterable { }` | For-of style |
|
|
977
|
+
| `foreach(col)(key, val) { }` | Key-value iteration |
|
|
978
|
+
| `foreach(col)(key, val, len) { }` | With length variable |
|
|
979
|
+
|
|
980
|
+
**State:**
|
|
981
|
+
|
|
982
|
+
| Keyword | Behavior |
|
|
983
|
+
|---------|----------|
|
|
984
|
+
| `backup x = x` | Save value to executor backup store |
|
|
985
|
+
| `retrieve x` | Restore from backup store |
|
|
986
|
+
| `addto arr val` | Push value to array |
|
|
987
|
+
| `addto map val : key` | Set `map[key] = val` |
|
|
988
|
+
|
|
989
|
+
**Async Tasks:**
|
|
990
|
+
|
|
991
|
+
| Keyword | Behavior |
|
|
992
|
+
|---------|----------|
|
|
993
|
+
| `gear(ms) name { }` | Named loop task; waits `ms` between iterations |
|
|
994
|
+
| `gear name { }` | Named loop task; no wait |
|
|
995
|
+
| `engage a >> b` | Run gears left-to-right in continuous loop until `break` |
|
|
996
|
+
|
|
997
|
+
**Isolation:**
|
|
998
|
+
|
|
999
|
+
| Keyword | Behavior |
|
|
1000
|
+
|---------|----------|
|
|
1001
|
+
| `sandbox { }` | Run in isolated Node.js vm context; scope vars snapshotted in/out |
|
|
1002
|
+
| `infer ("model") => var: "prompt"` | Run local AI model via `ollama` |
|
|
1003
|
+
|
|
1004
|
+
**Data:**
|
|
1005
|
+
|
|
1006
|
+
| Keyword | Behavior |
|
|
1007
|
+
|---------|----------|
|
|
1008
|
+
| `sstream name => { put val }` | Named sync stream with `put` accumulator |
|
|
1009
|
+
| `lend fn src to dst` | Merge `src` function body into `dst` |
|
|
1010
|
+
| `lend m map with fn` | Attach `fn` as method on `map` object |
|
|
1011
|
+
|
|
1012
|
+
**Session / Resumable:**
|
|
1013
|
+
|
|
1014
|
+
| Keyword | Behavior |
|
|
1015
|
+
|---------|----------|
|
|
1016
|
+
| `session("name") { }` | Store named session body |
|
|
1017
|
+
| `enter key type` | Log `[enter] key type` — interactive entry point marker |
|
|
1018
|
+
| `resu name(args) => { },` | Resumable: re-parsed and run fresh on each call |
|
|
1019
|
+
| `keyfunc name(x) { } { }` | Pattern-matched function dispatch |
|
|
1020
|
+
|
|
1021
|
+
**Annotation / Registry:**
|
|
1022
|
+
|
|
1023
|
+
| Keyword | Behavior |
|
|
1024
|
+
|---------|----------|
|
|
1025
|
+
| `describe "text"` | Append to `nova.descriptions` |
|
|
1026
|
+
| `using flagName` | Set `this.options[flag] = true` |
|
|
1027
|
+
| `unuse flagName` | Delete `this.options[flag]` |
|
|
1028
|
+
| `using namespace MyNS` | Bring all namespace members into scope |
|
|
1029
|
+
|
|
1030
|
+
**Type Ops:**
|
|
1031
|
+
|
|
1032
|
+
| Keyword | Behavior |
|
|
1033
|
+
|---------|----------|
|
|
1034
|
+
| `classify value` | Print/return type string |
|
|
1035
|
+
| `classify value as Type` | Return bool |
|
|
1036
|
+
| `rate(v) type` | Type-cast (see full table in Type System section) |
|
|
1037
|
+
|
|
1038
|
+
**Control:**
|
|
1039
|
+
|
|
1040
|
+
| Keyword | Behavior |
|
|
1041
|
+
|---------|----------|
|
|
1042
|
+
| `skip` | No-op (parsed, returns undefined) |
|
|
1043
|
+
| `end` | Terminate current scope: throws `{ __return: undefined }` |
|
|
1044
|
+
| `clear` | Reset `nova.descriptions` to `[]` |
|
|
1045
|
+
| `time { }` | Time a block; print elapsed ms |
|
|
1046
|
+
| `wait(ms)` | Sync sleep via Atomics.wait |
|
|
1047
|
+
|
|
1048
|
+
**Misc:**
|
|
1049
|
+
|
|
1050
|
+
| Keyword | Behavior |
|
|
1051
|
+
|---------|----------|
|
|
1052
|
+
| `expt "val" from { }` | Capture stdout; error if `actual.trim() !== "val"` |
|
|
1053
|
+
| `option name = fn` | Set runtime option/hook |
|
|
1054
|
+
| `env VAR` | Read `process.env.VAR` into scope; throws if undefined |
|
|
1055
|
+
| `eval expr` | Re-evaluate an already-parsed AST node |
|
|
1056
|
+
| `declare (expr) as x` | Assign to `x` |
|
|
1057
|
+
| `declare (expr) into x` | Append string to `x` |
|
|
1058
|
+
| `declare (expr) as x log` | Assign and print |
|
|
1059
|
+
| `declare (expr) as x throw` | Assign and throw |
|
|
1060
|
+
| `declare (expr) as x finalize` | Assign and `return` |
|
|
1061
|
+
|
|
1062
|
+
|
|
1063
|
+
## Built-in Global Objects
|
|
1064
|
+
|
|
1065
|
+
Always in scope — no import needed.
|
|
1066
|
+
|
|
1067
|
+
### `core`
|
|
1068
|
+
|
|
1069
|
+
| Member | Description |
|
|
1070
|
+
|--------|-------------|
|
|
1071
|
+
| `core.print(v)` | `process.stdout.write(stringify(v) + '\n')` |
|
|
1072
|
+
| `core.json` | Reference to `JSON` |
|
|
1073
|
+
| `core.getAst()` | Returns current program AST |
|
|
1074
|
+
| `core.vars` | Reference to global scope variables |
|
|
1075
|
+
| `core.types` | Reference to the TypeRegistry |
|
|
1076
|
+
| `core.register(fn)` | Wraps a novac function as a native callable |
|
|
1077
|
+
| `core.import` | Module import function |
|
|
1078
|
+
| `core.ndb()` | Dev bridge: `{ exe, scopes, types, eventBus, gears, backups, macros, blocks, snippets, keyfuncs, sessions, resus, namespaces }` |
|
|
1079
|
+
|
|
1080
|
+
### `nova` (Unified Registry)
|
|
1081
|
+
|
|
1082
|
+
Live proxy over all internal registries:
|
|
1083
|
+
|
|
1084
|
+
| Member | Description |
|
|
1085
|
+
|--------|-------------|
|
|
1086
|
+
| `nova.version` | `"2.0"` |
|
|
1087
|
+
| `nova.macros` | All defined macros |
|
|
1088
|
+
| `nova.blocks` | All defined blocks |
|
|
1089
|
+
| `nova.snippets` | All defined snippets |
|
|
1090
|
+
| `nova.gears` | All defined gears |
|
|
1091
|
+
| `nova.sessions` | All defined sessions |
|
|
1092
|
+
| `nova.resus` | All defined resus |
|
|
1093
|
+
| `nova.keyfuncs` | All defined keyfuncs |
|
|
1094
|
+
| `nova.backups` | All backed-up values |
|
|
1095
|
+
| `nova.options` | Current option flags |
|
|
1096
|
+
| `nova.descriptions` | Array of all `describe` annotations |
|
|
1097
|
+
| `nova.scope` | Reference to global scope |
|
|
1098
|
+
| `nova.types.structs` | Registered struct names |
|
|
1099
|
+
| `nova.types.interfaces` | Registered interface names |
|
|
1100
|
+
| `nova.types.enums` | Registered enum names |
|
|
1101
|
+
| `nova.types.traits` | Registered trait names |
|
|
1102
|
+
| `nova.types.check(val, typeName)` | Runtime type check → bool |
|
|
1103
|
+
| `nova.types.list()` | All registered type names |
|
|
1104
|
+
| `nova.events.events()` | Active event names |
|
|
1105
|
+
| `nova.events.count(ev)` | Number of listeners |
|
|
1106
|
+
| `nova.events.has(ev)` | Has listeners? |
|
|
1107
|
+
| `nova.events.clear(ev)` | Remove all listeners for event |
|
|
1108
|
+
| `nova.events.clearAll()` | Remove all events |
|
|
1109
|
+
| `nova.setMacro(name, val)` | Define/update a macro |
|
|
1110
|
+
| `nova.getMacro(name)` | Get macro value |
|
|
1111
|
+
| `nova.hasMacro(name)` | Check if macro exists |
|
|
1112
|
+
| `nova.setBlock(name, fn)` | Register a native block |
|
|
1113
|
+
| `nova.runBlock(name)` | Execute a named block |
|
|
1114
|
+
| `nova.runSnippet(name, ...args)` | Execute a named snippet |
|
|
1115
|
+
| `nova.emit(event, val)` | Emit event |
|
|
1116
|
+
| `nova.on(event, fn)` | Listen for event |
|
|
1117
|
+
| `nova.eval(code)` | Parse and run a novac code string |
|
|
1118
|
+
| `nova.inspect(name)` | `{ inScope, isMacro, isBlock, isSnippet, isGear, isSession, isResu, value }` |
|
|
1119
|
+
| `nova.clearAll()` | Clear macros, blocks, snippets, gears, sessions, descriptions |
|
|
1120
|
+
|
|
1121
|
+
### `nvk` (Platform / System Namespace)
|
|
1122
|
+
|
|
1123
|
+
`nvk` exposes all system and I/O operations. These replaced the previous statement-based system keywords.
|
|
1124
|
+
|
|
1125
|
+
| Member | Description |
|
|
1126
|
+
|--------|-------------|
|
|
1127
|
+
| `nvk.notify(title, content)` | Termux notification (fallback: stdout) |
|
|
1128
|
+
| `nvk.toast(msg)` | Termux toast |
|
|
1129
|
+
| `nvk.vibrate(ms)` | Termux vibrate |
|
|
1130
|
+
| `nvk.clipboard(text)` | Set clipboard via Termux |
|
|
1131
|
+
| `nvk.camera(path)` | Take photo via Termux |
|
|
1132
|
+
| `nvk.share(path)` | Share file via Termux |
|
|
1133
|
+
| `nvk.open(path)` | Open file via Termux |
|
|
1134
|
+
| `nvk.cpu` | Array of CPU model strings |
|
|
1135
|
+
| `nvk.mem` | Total memory e.g. `"8.00GB"` |
|
|
1136
|
+
| `nvk.hostname` | `os.hostname()` |
|
|
1137
|
+
| `nvk.uptime` | `os.uptime()` in seconds |
|
|
1138
|
+
| `nvk.pid` | `process.pid` |
|
|
1139
|
+
| `nvk.arch` | `os.arch()` |
|
|
1140
|
+
| `nvk.platform` | `process.platform` |
|
|
1141
|
+
| `nvk.osPlatform` | `os.platform()` |
|
|
1142
|
+
| `nvk.userInfo` | `os.userInfo()` as NovaObject |
|
|
1143
|
+
| `nvk.network` | `os.networkInterfaces()` as NovaObject |
|
|
1144
|
+
| `nvk.load` | `os.loadavg()` as NovaArray |
|
|
1145
|
+
| `nvk.tmpDir` | `os.tmpdir()` |
|
|
1146
|
+
| `nvk.cwd` | `process.cwd()` |
|
|
1147
|
+
| `nvk.pathDir(p)` | `path.dirname(p)` |
|
|
1148
|
+
| `nvk.pathBase(p)` | `path.basename(p)` |
|
|
1149
|
+
| `nvk.pathExt(p)` | `path.extname(p)` |
|
|
1150
|
+
| `nvk.pathJoin(...parts)` | `path.join(...parts)` |
|
|
1151
|
+
| `nvk.sha256(s)` | SHA-256 hex digest |
|
|
1152
|
+
| `nvk.randomBytes(n)` | N random bytes as hex string |
|
|
1153
|
+
| `nvk.uuid()` | Random UUID v4 |
|
|
1154
|
+
| `nvk.parseURL(raw)` | `{ hostname, pathname, search, protocol, port }` |
|
|
1155
|
+
| `nvk.readFile(path)` | `fs.readFileSync(path, 'utf8')` |
|
|
1156
|
+
| `nvk.writeFile(path, content)` | `fs.writeFileSync` |
|
|
1157
|
+
| `nvk.createFile(path, content)` | Create/overwrite file |
|
|
1158
|
+
| `nvk.deleteFile(path)` | `fs.unlinkSync` |
|
|
1159
|
+
| `nvk.listFiles(dir)` | `fs.readdirSync(dir)` as NovaArray |
|
|
1160
|
+
| `nvk.exists(path)` | `fs.existsSync(path)` |
|
|
1161
|
+
| `nvk.execFile(path)` | Parse and run a `.nova` file |
|
|
1162
|
+
| `nvk.sh(cmd)` | `execSync(cmd)` — prints and returns stdout |
|
|
1163
|
+
| `nvk.exec(code)` | Parse and run a novac code string |
|
|
1164
|
+
| `nvk.term(cmd, shell)` | Run cmd in specified shell (`bash` default) |
|
|
1165
|
+
| `nvk.banner(text)` | Print box-drawn banner |
|
|
1166
|
+
| `nvk.warn(msg)` | `"Warning: msg"` |
|
|
1167
|
+
| `nvk.info(msg)` | `"INFO: msg"` |
|
|
1168
|
+
|
|
1169
|
+
### `qae` (Query Assertion Engine)
|
|
1170
|
+
|
|
1171
|
+
All members are functions `(a) => bool` or `(a) => value`:
|
|
1172
|
+
|
|
1173
|
+
| Member | Description |
|
|
1174
|
+
|--------|-------------|
|
|
1175
|
+
| `qae.even(a)` / `qae.odd(a)` | Parity check |
|
|
1176
|
+
| `qae.integer(a)` | `Number.isInteger(a)` |
|
|
1177
|
+
| `qae.positive(a)` / `qae.negative(a)` / `qae.zero(a)` | Sign check |
|
|
1178
|
+
| `qae.finite_(a)` / `qae.infinite(a)` / `qae.nan_(a)` | Numeric state |
|
|
1179
|
+
| `qae.isnull(a)` / `qae.defined(a)` | Nullability |
|
|
1180
|
+
| `qae.trimable(a)` / `qae.trimmed(a)` | Whitespace |
|
|
1181
|
+
| `qae.uppercase(a)` / `qae.lowercase(a)` | Case transform |
|
|
1182
|
+
| `qae.numeric(a)` / `qae.alpha(a)` / `qae.alnum(a)` / `qae.blank(a)` | String class |
|
|
1183
|
+
| `qae.palindrome(a)` | Is palindrome (case-insensitive, strips spaces) |
|
|
1184
|
+
| `qae.empty(a)` / `qae.nonempty(a)` | Emptiness |
|
|
1185
|
+
| `qae.unique(a)` | Array has no duplicates |
|
|
1186
|
+
| `qae.first(a)` / `qae.last(a)` / `qae.length(a)` | Array/string access |
|
|
1187
|
+
| `qae.truthy(a)` / `qae.falsy(a)` | Boolean coercion |
|
|
1188
|
+
| `qae.type_(a)` | `typeof a` |
|
|
1189
|
+
| `qae.string_(a)` / `qae.number_(a)` / `qae.boolean_(a)` / `qae.object_(a)` / `qae.array_(a)` / `qae.function_(a)` | Type checks |
|
|
1190
|
+
| `qae.prime(a)` / `qae.composite(a)` / `qae.oddprime(a)` | Number theory |
|
|
1191
|
+
| `qae.vowel(a)` / `qae.consonant(a)` | Character class |
|
|
1192
|
+
| `qae.sorted(a)` / `qae.ascending(a)` / `qae.descending(a)` | Order checks |
|
|
1193
|
+
| `qae.contains(a, b)` / `qae.startsWith_(a, b)` / `qae.endsWith_(a, b)` / `qae.matches_(a, b)` | Containment |
|
|
1194
|
+
| `qae.divisible(a, b)` / `qae.between_(a, lo, hi)` | Numeric predicates |
|
|
1195
|
+
| `qae.check(a, pred)` | Apply function or named qae predicate to a |
|
|
1196
|
+
|
|
1197
|
+
### `novaRegex(pattern, flags)`
|
|
1198
|
+
|
|
1199
|
+
Semantic regex with `<name>` placeholders. Returns a JS `RegExp`.
|
|
1200
|
+
|
|
1201
|
+
```nova
|
|
1202
|
+
let emailRe = novaRegex("<email>")
|
|
1203
|
+
emailRe.test("a@b.com") // true
|
|
1204
|
+
novaRegex("<email|url>") // combined with |
|
|
437
1205
|
```
|
|
438
1206
|
|
|
439
|
-
|
|
1207
|
+
Semantic names: `keyword` `symbol` `digit` `nondigit` `whitespace` `tab` `newline` `start` `end` `any` `wordboundary` `word` `variable` `integer` `float` `hex` `binary` `space` `title` `email` `url` `uuid` `date` `time` `color`
|
|
1208
|
+
|
|
1209
|
+
### Global Functions
|
|
1210
|
+
|
|
1211
|
+
| Function | Description |
|
|
1212
|
+
|----------|-------------|
|
|
1213
|
+
| `typeOf(v)` | `"number"` `"string"` `"bool"` `"null"` `"array"` `"object"` `"range"` `"pointer"` `"function"` `"struct:Name"` `"enum:Name"` |
|
|
1214
|
+
| `typecheck(v, typeName)` | Runtime type check → bool |
|
|
1215
|
+
| `satisfies(v, ifaceName)` | Does value satisfy all required interface members? |
|
|
1216
|
+
| `fetch(url, options?)` | Sync HTTP → `{ ok, status, body, text }` |
|
|
1217
|
+
| `setTimeout(fn, delay)` | Schedule function after delay |
|
|
1218
|
+
|
|
1219
|
+
---
|
|
1220
|
+
|
|
1221
|
+
## Built-in Class Objects
|
|
1222
|
+
|
|
1223
|
+
All available globally:
|
|
1224
|
+
|
|
1225
|
+
### `ForLoop(opts)`
|
|
440
1226
|
|
|
441
1227
|
```nova
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
1228
|
+
ForLoop({ from: 1, to: 10 }).map(i => i * i).collect()
|
|
1229
|
+
ForLoop({ from: 0, to: 20, step: 2 }).toArray()
|
|
1230
|
+
ForLoop({ from: 1, to: 100 }).do(i => { sum += i }).run()
|
|
1231
|
+
```
|
|
1232
|
+
|
|
1233
|
+
| Method | Description |
|
|
1234
|
+
|--------|-------------|
|
|
1235
|
+
| `.from(n)` `.to(n)` `.step(n)` | Configure range |
|
|
1236
|
+
| `.do(fn)` / `.each(fn)` / `.map(fn)` | Set body |
|
|
1237
|
+
| `.run()` | Execute without collecting |
|
|
1238
|
+
| `.collect()` | Execute and collect results |
|
|
1239
|
+
| `.toArray()` | Collect index values |
|
|
1240
|
+
| `.filter(fn)` | Convert to Pipeline then filter |
|
|
1241
|
+
| `.pipe()` | Convert to Pipeline |
|
|
1242
|
+
| `.toStream()` | Convert to DataStream |
|
|
1243
|
+
|
|
1244
|
+
### `WhileLoop(opts)`
|
|
446
1245
|
|
|
447
|
-
|
|
448
|
-
|
|
1246
|
+
```nova
|
|
1247
|
+
WhileLoop({}).cond(() => n < 32).do(() => { n *= 2 }).maxIter(100).run()
|
|
449
1248
|
```
|
|
450
1249
|
|
|
451
|
-
###
|
|
1250
|
+
### `IfBlock(opts)`
|
|
452
1251
|
|
|
453
1252
|
```nova
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
1253
|
+
IfBlock({ cond: score >= 90, then: () => "A" })
|
|
1254
|
+
.elseIf(score >= 80, () => "B").else(() => "F").run()
|
|
1255
|
+
```
|
|
457
1256
|
|
|
458
|
-
|
|
459
|
-
lambda square = x => x * x;
|
|
1257
|
+
### `MatchBlock(subject)`
|
|
460
1258
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
1259
|
+
```nova
|
|
1260
|
+
MatchBlock(404)
|
|
1261
|
+
.when(200, () => "OK")
|
|
1262
|
+
.when(404, () => "Not Found")
|
|
1263
|
+
.when(90..100, x => "A")
|
|
1264
|
+
.when(x => x > 500, x => "server err")
|
|
1265
|
+
.default(() => "Unknown")
|
|
1266
|
+
.run()
|
|
1267
|
+
```
|
|
465
1268
|
|
|
466
|
-
|
|
467
|
-
func multiply(a, b) => { give a * b; }
|
|
468
|
-
partial double = multiply(2);
|
|
1269
|
+
### `TryCatch()`
|
|
469
1270
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
1271
|
+
```nova
|
|
1272
|
+
TryCatch().try(() => { throw "oops" }).catch(e => core.print(e)).finally(() => {}).run()
|
|
1273
|
+
```
|
|
1274
|
+
|
|
1275
|
+
### `Pipeline(initial)`
|
|
474
1276
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
snippet cleanup { core.print("cleanup run"); }
|
|
1277
|
+
```nova
|
|
1278
|
+
Pipeline([1,2,3,4,5]).filter(x => x % 2 == 0).map(x => x*x).take(2).collect()
|
|
478
1279
|
```
|
|
479
1280
|
|
|
480
|
-
|
|
1281
|
+
| Method | Description |
|
|
1282
|
+
|--------|-------------|
|
|
1283
|
+
| `.pipe(fn)` / `.map(fn)` | Transform |
|
|
1284
|
+
| `.filter(fn)` | Filter |
|
|
1285
|
+
| `.tap(fn)` | Side-effect passthrough |
|
|
1286
|
+
| `.flatMap(fn)` | Map + flatten |
|
|
1287
|
+
| `.reduce(fn, init)` | Immediate reduce |
|
|
1288
|
+
| `.take(n)` / `.skip(n)` | Slice |
|
|
1289
|
+
| `.run()` / `.collect()` | Execute |
|
|
1290
|
+
|
|
1291
|
+
### `FuncDef(opts)`
|
|
481
1292
|
|
|
482
1293
|
```nova
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
backup session = session;
|
|
486
|
-
let session = "guest";
|
|
487
|
-
retrieve session;
|
|
488
|
-
core.print(session); // user_abc
|
|
1294
|
+
FuncDef({ args: ["a", "b"], body: (a, b) => a + b }).named("add").call(10, 32)
|
|
1295
|
+
```
|
|
489
1296
|
|
|
490
|
-
|
|
491
|
-
|
|
1297
|
+
### `Timer()`
|
|
1298
|
+
|
|
1299
|
+
```nova
|
|
1300
|
+
let t = Timer(); t.start(); t.lap(); let ms = t.stop()
|
|
1301
|
+
t.elapsed // ms since start
|
|
1302
|
+
t.laps // NovaArray of lap times
|
|
492
1303
|
```
|
|
493
1304
|
|
|
494
|
-
###
|
|
1305
|
+
### `Counter(initial, step)`
|
|
495
1306
|
|
|
496
1307
|
```nova
|
|
497
|
-
|
|
498
|
-
unuse strictMode; // disable it
|
|
1308
|
+
let c = Counter(0); c.increment(5); c.decrement(2); c.clamp(0, 100); c.value
|
|
499
1309
|
```
|
|
500
1310
|
|
|
501
|
-
###
|
|
1311
|
+
### `Stack()` / `Queue()` / `LinkedList()`
|
|
502
1312
|
|
|
503
1313
|
```nova
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
true xnor true // true — not xor
|
|
1314
|
+
let s = Stack(); s.push(10); s.pop(); s.peek(); s.size; s.empty
|
|
1315
|
+
let q = Queue(); q.enqueue("a"); q.dequeue(); q.peek(); q.size
|
|
1316
|
+
let ll = LinkedList(); ll.push("a"); ll.shift(); ll.pop(); ll.unshift("z"); ll.size
|
|
1317
|
+
```
|
|
509
1318
|
|
|
510
|
-
|
|
511
|
-
42 is 42 // true — strict identity
|
|
512
|
-
1 isnt 2 // true — not identical
|
|
513
|
-
42 istypeof "number" // true
|
|
514
|
-
"hello" matches "hell" // regex test
|
|
1319
|
+
### `State(initial)`
|
|
515
1320
|
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
1321
|
+
```nova
|
|
1322
|
+
let sm = State("idle")
|
|
1323
|
+
sm.add("idle", "start", "running").add("running", "done", "idle")
|
|
1324
|
+
sm.onEnter("running", s => {}).onExit("idle", s => {})
|
|
1325
|
+
sm.dispatch("start") // true = success
|
|
1326
|
+
sm.current; sm.history; sm.is("running")
|
|
1327
|
+
```
|
|
521
1328
|
|
|
522
|
-
|
|
523
|
-
4 avg 6 // 5
|
|
524
|
-
12 gcd 8 // 4
|
|
525
|
-
4 lcm 6 // 12
|
|
526
|
-
"a" cmp "b" // -1 (locale compare)
|
|
527
|
-
"Hello" equals_ignore "hello" // true
|
|
1329
|
+
### `Observable(initial)` / `Signal(initial)`
|
|
528
1330
|
|
|
529
|
-
|
|
530
|
-
|
|
1331
|
+
```nova
|
|
1332
|
+
let obs = Observable(0)
|
|
1333
|
+
obs.subscribe((newVal, oldVal) => {})
|
|
1334
|
+
obs.value = 42
|
|
1335
|
+
let derived = obs.pipe(x => x * 2)
|
|
1336
|
+
|
|
1337
|
+
let sig = Signal(1)
|
|
1338
|
+
let doubled = sig.derive(x => x * 2)
|
|
1339
|
+
sig.value = 5 // doubled.value = 10 (automatic propagation)
|
|
1340
|
+
sig.effect(v => {}) // runs immediately and on every change
|
|
1341
|
+
```
|
|
1342
|
+
|
|
1343
|
+
### `Validator()`
|
|
531
1344
|
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
1345
|
+
```nova
|
|
1346
|
+
Validator().required().type("number").min(0).max(100).validate(50)
|
|
1347
|
+
// { valid: true, errors: [], value: 50 }
|
|
535
1348
|
```
|
|
536
1349
|
|
|
537
|
-
|
|
1350
|
+
| Method | Description |
|
|
1351
|
+
|--------|-------------|
|
|
1352
|
+
| `.required()` `.type(t)` `.min(n)` `.max(n)` | Core validators |
|
|
1353
|
+
| `.minLen(n)` `.maxLen(n)` `.pattern(re)` `.email()` | String validators |
|
|
1354
|
+
| `.custom(fn, msg)` | Custom validator |
|
|
1355
|
+
| `.validate(v)` | Returns `{ valid, errors: NovaArray, value }` |
|
|
1356
|
+
|
|
1357
|
+
### `DataStream(source)`
|
|
1358
|
+
|
|
1359
|
+
```nova
|
|
1360
|
+
DataStream([5,3,8,1,9]).filter(x => x > 3).sort().reverse().take(3).collect()
|
|
1361
|
+
```
|
|
1362
|
+
|
|
1363
|
+
| Method | Description |
|
|
1364
|
+
|--------|-------------|
|
|
1365
|
+
| `.map` `.filter` `.take` `.skip` `.flatMap` | Transform |
|
|
1366
|
+
| `.distinct()` | Deduplicate via Set |
|
|
1367
|
+
| `.sort(fn?)` `.reverse()` `.zip(other)` | Reorder |
|
|
1368
|
+
| `.collect()` `.reduce(fn, init)` `.forEach(fn)` | Materialize |
|
|
1369
|
+
| `.first()` `.last()` `.count()` | Inspect |
|
|
1370
|
+
|
|
1371
|
+
### `Transformer()` / `TransformerJSON()` / `TransformerBase64()`
|
|
538
1372
|
|
|
539
1373
|
```nova
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
rate(300) u16 // 300
|
|
544
|
-
rate(5) bigint // 5n
|
|
545
|
-
rate("hi") char // "h"
|
|
546
|
-
rate(1.5) f32 // 32-bit float precision
|
|
1374
|
+
let jt = TransformerJSON(); jt.to({ x: 1 }); jt.from('{"x":1}')
|
|
1375
|
+
let b64 = TransformerBase64(); b64.to("Hello!"); b64.from(encoded)
|
|
1376
|
+
// Static presets: Transformer.upper(), Transformer.trim_(), Transformer.number_()
|
|
547
1377
|
```
|
|
548
1378
|
|
|
549
|
-
###
|
|
1379
|
+
### `Router()`
|
|
550
1380
|
|
|
551
1381
|
```nova
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
classify 42 as int // true
|
|
556
|
-
classify "x" as int // false
|
|
1382
|
+
let router = Router()
|
|
1383
|
+
router.on("/api/users/(.*)", id => f"user {id}").default(p => f"404: {p}")
|
|
1384
|
+
router.dispatch("/api/users/42") // "user 42"
|
|
557
1385
|
```
|
|
558
1386
|
|
|
559
|
-
###
|
|
1387
|
+
### `EventBus()`
|
|
560
1388
|
|
|
561
1389
|
```nova
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
qae.ascending([1,2,3]) // true
|
|
566
|
-
qae.blank("") // true
|
|
567
|
-
qae.contains([1,2],2) // true
|
|
568
|
-
qae.vowel("a") // true
|
|
569
|
-
qae.divisible(12, 4) // true
|
|
570
|
-
qae.between_(5, 1, 10)// true
|
|
571
|
-
// 40+ predicates total
|
|
1390
|
+
let bus = EventBus()
|
|
1391
|
+
bus.on("data", v => {}).once("ready", () => {}).off("data", handler)
|
|
1392
|
+
bus.emit("data", 42); bus.events()
|
|
572
1393
|
```
|
|
573
1394
|
|
|
574
|
-
###
|
|
1395
|
+
### `Memo(fn, keyFn?)` / `Lazy(fn)`
|
|
575
1396
|
|
|
576
1397
|
```nova
|
|
577
|
-
let
|
|
578
|
-
|
|
579
|
-
let urlRx = novaRegex("<url>");
|
|
580
|
-
emailRx.test("a@b.com"); // true
|
|
1398
|
+
let m = Memo(x => x * x * x)
|
|
1399
|
+
m.call(5); m.stats; m.clear(); m.invalidate(5)
|
|
581
1400
|
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
// email, url, uuid, date, time, color, hex, binary, title, etc.
|
|
1401
|
+
let lazy = Lazy(() => expensiveOp())
|
|
1402
|
+
lazy.value; lazy.reset(); lazy.map(fn)
|
|
585
1403
|
```
|
|
586
1404
|
|
|
587
|
-
|
|
1405
|
+
---
|
|
1406
|
+
|
|
1407
|
+
## Standard Library (`std`)
|
|
1408
|
+
|
|
1409
|
+
Always available as `std.X`.
|
|
1410
|
+
|
|
1411
|
+
### `std.Math`
|
|
1412
|
+
|
|
1413
|
+
`abs` `ceil` `floor` `round` `sqrt` `pow` `max` `min` `log` `log2` `log10` `sin` `cos` `tan` `PI` `E` `trunc` `sign` `random` plus:
|
|
1414
|
+
|
|
1415
|
+
| Member | Description |
|
|
1416
|
+
|--------|-------------|
|
|
1417
|
+
| `clamp(v, lo, hi)` | `Math.min(Math.max(v,lo),hi)` |
|
|
1418
|
+
| `floorTo(a, b)` | Floor to nearest multiple of b |
|
|
1419
|
+
| `ceilTo(a, b)` | Ceil to nearest multiple of b |
|
|
1420
|
+
| `factorial(n)` | Memoized factorial |
|
|
1421
|
+
| `fibonacci(n)` | Memoized fibonacci |
|
|
1422
|
+
| `divmod(a, b)` | `[quotient, remainder]` |
|
|
1423
|
+
|
|
1424
|
+
### `std.Array`
|
|
1425
|
+
|
|
1426
|
+
`from(it)` `of(...items)` `range(start, end, step)` `isArray(v)` `fill(n, val)` `zip(...arrs)`
|
|
1427
|
+
|
|
1428
|
+
### `std.Object`
|
|
1429
|
+
|
|
1430
|
+
`keys(o)` `values(o)` `entries(o)` `assign(target, ...srcs)` `freeze(o)` `has(o, k)` `create(proto)`
|
|
1431
|
+
|
|
1432
|
+
### `std.String`
|
|
1433
|
+
|
|
1434
|
+
`from(v)` `padStart` `padEnd` `repeat` `includes` `startsWith` `endsWith` `trim` `split` `replace` `replaceAll` `toUpper` `toLower` `charAt` `charCodeAt` `fromCharCode` `slice` `indexOf`
|
|
1435
|
+
|
|
1436
|
+
### `std.is`
|
|
588
1437
|
|
|
589
1438
|
```nova
|
|
590
|
-
std.
|
|
591
|
-
std.
|
|
592
|
-
std.
|
|
593
|
-
std.randomWord() // random pronounceable word
|
|
594
|
-
std.randomName() // random first name
|
|
1439
|
+
std.is.number(v) std.is.string(v) std.is.bool(v) std.is.array(v)
|
|
1440
|
+
std.is.object(v) std.is.null(v) std.is.func(v) std.is.range(v)
|
|
1441
|
+
std.is.integer(v) std.is.finite(v) std.is.NaN(v)
|
|
595
1442
|
```
|
|
596
1443
|
|
|
1444
|
+
### `std.fn`
|
|
1445
|
+
|
|
1446
|
+
`identity` `compose` `pipe` `memoize` `once` `partial` `curry` `noop` `always` `flip` `not`
|
|
1447
|
+
|
|
1448
|
+
### Other `std` Members
|
|
1449
|
+
|
|
1450
|
+
| Member | Description |
|
|
1451
|
+
|--------|-------------|
|
|
1452
|
+
| `std.num(v)` / `std.str(v)` / `std.bool(v)` / `std.int(v)` | Coercions |
|
|
1453
|
+
| `std.print(...)` | `console.log(...)` |
|
|
1454
|
+
| `std.error(msg)` | Throw an Error |
|
|
1455
|
+
| `std.range(start, end, step)` | Create NovaRange |
|
|
1456
|
+
| `std.fnum(min, max, initial)` | Clamped float with `.value` get/set |
|
|
1457
|
+
| `std.fint(min, max, initial)` | Clamped integer with `.value` get/set |
|
|
1458
|
+
| `std.convertCase(str, target)` | `"snake"` `"camel"` `"pascal"` `"kebab"` `"upper"` `"lower"` |
|
|
1459
|
+
| `std.randomWord()` | Random pronounceable word |
|
|
1460
|
+
| `std.randomName(format?, minLen?, maxLen?)` | Capitalized random name |
|
|
1461
|
+
| `std.console.*` | `log warn error info time timeEnd` |
|
|
1462
|
+
| `std.Date.now()` / `std.Date.create(...)` | Date utilities |
|
|
1463
|
+
| `std.json.parse(s)` / `std.json.stringify(v, sp?)` | JSON with NovaObject unwrapping |
|
|
1464
|
+
| `std.Promise.*` | `resolve reject all race allSettled any` |
|
|
597
1465
|
|
|
598
1466
|
---
|
|
599
1467
|
|
|
600
|
-
##
|
|
1468
|
+
## Standard Built-ins (`bstd` / `import_builtin`)
|
|
1469
|
+
|
|
1470
|
+
### `Air`
|
|
601
1471
|
|
|
602
|
-
|
|
1472
|
+
Object of references to all novac core modules keyed by filename.
|
|
1473
|
+
|
|
1474
|
+
### `Chalk`
|
|
1475
|
+
|
|
1476
|
+
ANSI terminal colors (same API as `chalk` npm package):
|
|
603
1477
|
|
|
604
1478
|
```nova
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
nova.gears // all declared gears
|
|
610
|
-
nova.sessions // all declared sessions
|
|
611
|
-
nova.options // current feature flags
|
|
612
|
-
nova.descriptions // describe() annotations
|
|
613
|
-
nova.types // type registry (.structs, .interfaces, .enums, .traits)
|
|
614
|
-
nova.events // event bus view (.events(), .count(ev), .has(ev))
|
|
615
|
-
nova.version // "2.0"
|
|
1479
|
+
import_builtin Chalk
|
|
1480
|
+
core.print(Chalk.red("error"))
|
|
1481
|
+
core.print(Chalk.bold.green("success"))
|
|
1482
|
+
```
|
|
616
1483
|
|
|
617
|
-
|
|
618
|
-
nova.getMacro("KEY") // get a macro value
|
|
619
|
-
nova.hasMacro("KEY") // check existence
|
|
620
|
-
nova.setMacro("KEY", val) // set programmatically
|
|
1484
|
+
### `History`
|
|
621
1485
|
|
|
622
|
-
|
|
623
|
-
nova.runBlock("blockName") // execute a block
|
|
624
|
-
nova.runSnippet("snippetName", args) // execute a snippet with args
|
|
1486
|
+
File-backed input history stored as `.184.<name>`:
|
|
625
1487
|
|
|
626
|
-
|
|
627
|
-
nova.emit("eventName", value) // fire an event
|
|
628
|
-
nova.on("eventName", fn) // subscribe (native fn)
|
|
1488
|
+
`getKey(name)` `exists(key)` `createHistory(key)` `appendHistory(key, item, mode?, index?)` `readHistory(key)` `rawSetHistory(key, array)` `rawGetHistory(key)` `clearHistory(key)`
|
|
629
1489
|
|
|
630
|
-
|
|
631
|
-
let info = nova.inspect("myVar");
|
|
632
|
-
// info.inScope, info.isMacro, info.isBlock, info.value ...
|
|
1490
|
+
### `Input`
|
|
633
1491
|
|
|
634
|
-
|
|
635
|
-
let result = nova.eval("1 + 2 + 3");
|
|
1492
|
+
Synchronous terminal input with full line-editing:
|
|
636
1493
|
|
|
637
|
-
|
|
638
|
-
|
|
1494
|
+
```nova
|
|
1495
|
+
import_builtin Input
|
|
1496
|
+
let r = Input.prompt("Name: ")
|
|
1497
|
+
// r: { result: "typed text", history: [] }
|
|
1498
|
+
Input.prompt("Pwd: ", { password: true, passwordHash: "*" })
|
|
1499
|
+
Input.prompt("Cmd: ", true) // enable history
|
|
1500
|
+
Input.prompt("Search: ", { completer: buf => "suggestion" })
|
|
639
1501
|
```
|
|
640
1502
|
|
|
641
|
-
|
|
1503
|
+
Features: cursor, history `↑↓`, backspace, delete, tab completion, Ctrl+C, password masking.
|
|
642
1504
|
|
|
643
|
-
|
|
1505
|
+
### `Shema` / `ShemaType`
|
|
1506
|
+
|
|
1507
|
+
```nova
|
|
1508
|
+
import_builtin Shema, ShemaType
|
|
1509
|
+
let schema = new Shema({ name: ShemaTypes.String, age: ShemaTypes.Int })
|
|
1510
|
+
schema.validate({ name: "novac", age: 2 })
|
|
1511
|
+
schema.defaultObj()
|
|
1512
|
+
new ShemaType("PositiveInt", val => Number.isInteger(val) && val > 0)
|
|
1513
|
+
```
|
|
1514
|
+
|
|
1515
|
+
Built-in `ShemaTypes`: `Int` `Float` `String` `Boolean` `Array` `Object` `Function` `Null` `Undefined` `Symbol` `BigInt` `Date` `RegExp` `Shema` `Any`
|
|
644
1516
|
|
|
645
|
-
|
|
1517
|
+
### `ConfigFile`
|
|
646
1518
|
|
|
647
|
-
### `ForLoop`
|
|
648
1519
|
```nova
|
|
649
|
-
|
|
650
|
-
let
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
1520
|
+
import_builtin ConfigFile
|
|
1521
|
+
let cfg = new ConfigFile("app", "json", false, mySchema)
|
|
1522
|
+
cfg.writeFull({ host: "localhost", port: 8080 })
|
|
1523
|
+
cfg.write(["database", "host"], "db.example.com")
|
|
1524
|
+
cfg.readFull(); cfg.read(["database", "host"])
|
|
1525
|
+
cfg.interactiveSetup(defaultConfig)
|
|
1526
|
+
```
|
|
654
1527
|
|
|
655
|
-
|
|
656
|
-
|
|
1528
|
+
### `JsDB`
|
|
1529
|
+
|
|
1530
|
+
`JsDB.class(JsClass)` `JsDB.run(code)` `JsDB.require` `JsDB.gt` `JsDB.fetch(url, opts)` `JsDB.process` `JsDB.version` `JsDB.platform` `JsDB.env`
|
|
1531
|
+
|
|
1532
|
+
### `Storage`
|
|
1533
|
+
|
|
1534
|
+
```nova
|
|
1535
|
+
import_builtin Storage
|
|
1536
|
+
Storage.setItem("key", { data: 42 })
|
|
1537
|
+
Storage.getItem("key")
|
|
1538
|
+
Storage.removeItem("key")
|
|
1539
|
+
Storage.clear()
|
|
657
1540
|
```
|
|
658
1541
|
|
|
659
|
-
### `
|
|
1542
|
+
### `Crypto`
|
|
1543
|
+
|
|
660
1544
|
```nova
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
1545
|
+
import_builtin Crypto
|
|
1546
|
+
Crypto.hash("data") // SHA-256 hex
|
|
1547
|
+
Crypto.hash("data", "sha512") // any Node.js crypto algo
|
|
664
1548
|
```
|
|
665
1549
|
|
|
666
|
-
### `
|
|
1550
|
+
### `PathUtils`
|
|
1551
|
+
|
|
1552
|
+
`join` `resolve` `basename` `dirname` `extname`
|
|
1553
|
+
|
|
1554
|
+
### `Base64`
|
|
1555
|
+
|
|
1556
|
+
`Base64.encode(s)` `Base64.decode(s)`
|
|
1557
|
+
|
|
1558
|
+
### `OsUtils`
|
|
1559
|
+
|
|
1560
|
+
`platform` `homedir()` `tmpdir()` `cpus()` `totalmem()` `freemem()` `uptime()` `openFile(path)` (Windows: `requestAdminPrivileges()`)
|
|
1561
|
+
|
|
1562
|
+
### `Zip`
|
|
1563
|
+
|
|
667
1564
|
```nova
|
|
668
|
-
|
|
1565
|
+
import_builtin Zip
|
|
1566
|
+
await Zip.zip(["a.txt"], "out.zip")
|
|
1567
|
+
await Zip.unzip("out.zip", "./output/")
|
|
1568
|
+
```
|
|
1569
|
+
|
|
1570
|
+
---
|
|
1571
|
+
|
|
1572
|
+
## Array Methods
|
|
1573
|
+
|
|
1574
|
+
Auto-dispatched on any NovaArray:
|
|
669
1575
|
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
1576
|
+
`map` `filter` `reduce` `find` `findIndex` `some` `every` `flat` `flatMap` `sort` `reverse` `slice` `splice` `indexOf` `includes` `join` `push` `pop` `shift` `unshift` `concat` `fill` `forEach` `keys` `values` `entries` `at` `first` `last` `random` `unique` `count` `groupBy` `shuffle` `min` `max` `sum` `avg` `product` `toArray` `toObject` `toString` | `.length` (property)
|
|
1577
|
+
|
|
1578
|
+
---
|
|
1579
|
+
|
|
1580
|
+
## Object Methods
|
|
1581
|
+
|
|
1582
|
+
Auto-dispatched on any NovaObject:
|
|
1583
|
+
|
|
1584
|
+
`keys()` `values()` `entries()` `has(k)` `assign(...srcs)` | `.length` (property)
|
|
1585
|
+
|
|
1586
|
+
---
|
|
1587
|
+
|
|
1588
|
+
## String Methods
|
|
1589
|
+
|
|
1590
|
+
Auto-dispatched on any string:
|
|
1591
|
+
|
|
1592
|
+
`toUpperCase` `toLowerCase` `trim` `split` `includes` `startsWith` `endsWith` `slice` `indexOf` `lastIndexOf` `repeat` `replace` `match` | `.length` (property)
|
|
1593
|
+
|
|
1594
|
+
---
|
|
1595
|
+
|
|
1596
|
+
## Type System & Casting
|
|
1597
|
+
|
|
1598
|
+
### `as` Cast
|
|
1599
|
+
|
|
1600
|
+
```nova
|
|
1601
|
+
let n = value as int // Math.trunc(Number(v))
|
|
1602
|
+
let f = value as float // Number(v)
|
|
1603
|
+
let s = value as string // String(v)
|
|
1604
|
+
let b = value as bool // Boolean(v)
|
|
1605
|
+
let a = value as array // _toIterable(v) → NovaArray
|
|
1606
|
+
let st = value as MyStruct
|
|
676
1607
|
```
|
|
677
1608
|
|
|
678
|
-
### `
|
|
1609
|
+
### `rate()` Cast — Full Type Table
|
|
1610
|
+
|
|
1611
|
+
| Type | Operation |
|
|
1612
|
+
|------|-----------|
|
|
1613
|
+
| `int` | `Math.trunc(Number(v))` |
|
|
1614
|
+
| `float` / `f64` | `Number(v)` |
|
|
1615
|
+
| `f32` | `Math.fround(Number(v))` |
|
|
1616
|
+
| `string` | `String(v)` |
|
|
1617
|
+
| `bool` | `Boolean(v)` |
|
|
1618
|
+
| `bigint` | `BigInt(Math.trunc(Number(v)))` |
|
|
1619
|
+
| `u8` | `parseInt(v) & 0xFF` |
|
|
1620
|
+
| `u16` | `parseInt(v) & 0xFFFF` |
|
|
1621
|
+
| `u32` | `parseInt(v) >>> 0` |
|
|
1622
|
+
| `i8` | `(parseInt(v) << 24) >> 24` |
|
|
1623
|
+
| `i16` | `(parseInt(v) << 16) >> 16` |
|
|
1624
|
+
| `i32` | `parseInt(v) \| 0` |
|
|
1625
|
+
| `char` | `String(v)[0]` |
|
|
1626
|
+
| `array` | `_toIterable(v)` → NovaArray |
|
|
1627
|
+
| `StructName` | `createStruct("StructName", v)` |
|
|
1628
|
+
|
|
1629
|
+
### Type Check
|
|
1630
|
+
|
|
679
1631
|
```nova
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
1632
|
+
typecheck(42, "number") // true
|
|
1633
|
+
satisfies(doc, "Serializable") // true if all required interface members present
|
|
1634
|
+
classify value // returns type string
|
|
1635
|
+
classify value as TypeName // returns bool
|
|
1636
|
+
```
|
|
1637
|
+
|
|
1638
|
+
---
|
|
1639
|
+
|
|
1640
|
+
## CLI — novac
|
|
1641
|
+
|
|
1642
|
+
```sh
|
|
1643
|
+
novac <file> [args...] Run a .nova / .nv file
|
|
1644
|
+
novac test <file> Check syntax (exit 0 = OK, prints "Syntax OK")
|
|
1645
|
+
novac format [file] Format a file (or stdin if no file given)
|
|
1646
|
+
novac eval <code> Evaluate a novac code string inline
|
|
1647
|
+
novac tokens <file> Print token stream as JSON
|
|
1648
|
+
novac ast <file> Print AST as JSON
|
|
1649
|
+
novac repl Start interactive REPL
|
|
1650
|
+
novac new <project> Scaffold a new project directory
|
|
1651
|
+
novac new-kit <dirname> Scaffold a new kit in current directory
|
|
1652
|
+
novac init PATH Add npm bin to system PATH (writes to shell rc)
|
|
1653
|
+
novac init build Bundle project into a .novamod file
|
|
1654
|
+
novac config get [key] Read global/project config (all keys if no key given)
|
|
1655
|
+
novac config set <key> <value> Write a config key
|
|
1656
|
+
novac config init Interactive config setup wizard
|
|
1657
|
+
novac etc notices Show runtime notices from stdlib
|
|
1658
|
+
novac etc describe <file> Print a human-readable description of a .nova file's AST
|
|
1659
|
+
novac etc kit <name> Install a built-in kit into ./nova_modules/<name>
|
|
1660
|
+
novac etc kit <name> --global Install a built-in kit into ~/.novac/nova_modules/<name>
|
|
1661
|
+
novac module install [path] Install a .novamod bundle (or all deps from nova.config.json)
|
|
1662
|
+
novac module install [path] -g Install globally into ~/.novac/nova_modules
|
|
1663
|
+
novac module list List all installed modules in nova_modules/
|
|
1664
|
+
novac module remove <name> Remove an installed module
|
|
1665
|
+
```
|
|
1666
|
+
|
|
1667
|
+
### Running a File
|
|
1668
|
+
|
|
1669
|
+
```sh
|
|
1670
|
+
novac src/main.nova
|
|
1671
|
+
novac src/main.nova arg1 arg2
|
|
1672
|
+
novac src/main.nova --port 8080 --debug
|
|
1673
|
+
novac src/main.nova @addr1 +feature1
|
|
685
1674
|
```
|
|
686
1675
|
|
|
687
|
-
|
|
1676
|
+
All arguments after the file are parsed and exposed as the `cli` object inside the script (see below).
|
|
1677
|
+
|
|
1678
|
+
### Argument Parsing Rules
|
|
1679
|
+
|
|
1680
|
+
| Argument form | Goes into |
|
|
1681
|
+
|---------------|-----------|
|
|
1682
|
+
| `positional` (no prefix) | `cli.args` array |
|
|
1683
|
+
| `-flag` | `cli.options.flag = true` |
|
|
1684
|
+
| `--flag` | `cli.options.flag = true` |
|
|
1685
|
+
| `--flag value` | `cli.options.flag = "value"` |
|
|
1686
|
+
| `--flag=value` | `cli.options.flag = "value"` |
|
|
1687
|
+
| `@name` | `cli.addrs.name = true` |
|
|
1688
|
+
| `+feature` | `cli.additions.feature = true` |
|
|
1689
|
+
|
|
1690
|
+
Arguments that start with `-`, `@`, or `+` are **excluded** from `cli.args`.
|
|
1691
|
+
|
|
1692
|
+
### REPL Commands
|
|
1693
|
+
|
|
1694
|
+
Inside `novac repl`:
|
|
1695
|
+
|
|
1696
|
+
| Command | Description |
|
|
1697
|
+
|---------|-------------|
|
|
1698
|
+
| `.exit` | Exit the REPL |
|
|
1699
|
+
| `.clear` | Clear the screen |
|
|
1700
|
+
| `.ast <code>` | Print AST of inline code |
|
|
1701
|
+
| `.tokens <code>` | Print token stream of inline code |
|
|
1702
|
+
| `.help` | Show REPL help |
|
|
1703
|
+
|
|
1704
|
+
History is persisted to `~/.nova_repl_history`.
|
|
1705
|
+
|
|
1706
|
+
### `novac new <project>`
|
|
1707
|
+
|
|
1708
|
+
Scaffolds a project directory with:
|
|
1709
|
+
|
|
1710
|
+
```
|
|
1711
|
+
<project>/
|
|
1712
|
+
src/main.nova // starter file with print("Hello, Nova!")
|
|
1713
|
+
bin/<project>.nv // entry script (empty, chmod 755)
|
|
1714
|
+
nova_modules/ // local module directory
|
|
1715
|
+
nova.config.json // project manifest
|
|
1716
|
+
README.md
|
|
1717
|
+
.gitignore
|
|
1718
|
+
```
|
|
1719
|
+
|
|
1720
|
+
`nova.config.json` fields: `name`, `version`, `description`, `author`, `license`, `main`, `srcDir`, `scripts.run`, `dependencies`, `devDependencies`.
|
|
1721
|
+
|
|
1722
|
+
### `novac init build`
|
|
1723
|
+
|
|
1724
|
+
Reads `nova.config.json` from `cwd`, collects all `.nova`/`.nv` files from `srcDir`, and bundles them into `<name>.novamod` — a JSON file with:
|
|
1725
|
+
|
|
1726
|
+
```json
|
|
1727
|
+
{
|
|
1728
|
+
"manifest": { "name", "version", "main", ...config },
|
|
1729
|
+
"sources": { "relative/path.nova": "source code", ... },
|
|
1730
|
+
"buildTime": "ISO timestamp"
|
|
1731
|
+
}
|
|
1732
|
+
```
|
|
1733
|
+
|
|
1734
|
+
Install in another project: `novac module install ./<name>.novamod`
|
|
1735
|
+
|
|
1736
|
+
### `novac etc kit <name>`
|
|
1737
|
+
|
|
1738
|
+
Installs a built-in kit from `novac/kits/<name>/` into `nova_modules/`. Available built-in kits: `kitnovacweb`, `kitlibfs`, `kitlibproc`.
|
|
1739
|
+
|
|
1740
|
+
---
|
|
1741
|
+
|
|
1742
|
+
## Built-in `cli` Object
|
|
1743
|
+
|
|
1744
|
+
When a file is run via `novac <file> [args...]`, a `cli` object is automatically injected into the global scope:
|
|
1745
|
+
|
|
688
1746
|
```nova
|
|
689
|
-
|
|
690
|
-
.filter(x => x % 2 == 0)
|
|
691
|
-
.map(x => x * x)
|
|
692
|
-
.take(3)
|
|
693
|
-
.skip(1)
|
|
694
|
-
.collect();
|
|
1747
|
+
// novac myapp.nova hello world --port 8080 --debug @prod +cache
|
|
695
1748
|
|
|
696
|
-
//
|
|
697
|
-
|
|
1749
|
+
cli.args // ["hello", "world"] — positional args (no flag prefix)
|
|
1750
|
+
cli.options // { port: "8080", debug: true }
|
|
1751
|
+
cli.addrs // { prod: true }
|
|
1752
|
+
cli.additions // { cache: true }
|
|
1753
|
+
cli.raw // process.argv — full raw argument array
|
|
698
1754
|
```
|
|
699
1755
|
|
|
700
|
-
### `
|
|
1756
|
+
### Full `cli` Object Shape
|
|
1757
|
+
|
|
1758
|
+
| Property | Type | Description |
|
|
1759
|
+
|----------|------|-------------|
|
|
1760
|
+
| `cli.args` | Array | Positional arguments (no `-`, `@`, `+` prefix) |
|
|
1761
|
+
| `cli.options` | Object | All `-flag`, `--flag`, `--flag=val`, `--flag val` arguments |
|
|
1762
|
+
| `cli.addrs` | Object | All `@name` arguments, values are `true` |
|
|
1763
|
+
| `cli.additions` | Object | All `+name` arguments, values are `true` |
|
|
1764
|
+
| `cli.raw` | Array | `process.argv` — complete unprocessed argument list |
|
|
1765
|
+
|
|
1766
|
+
### Usage Examples
|
|
1767
|
+
|
|
701
1768
|
```nova
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
.run();
|
|
1769
|
+
// novac server.nova --port 3000 --host localhost
|
|
1770
|
+
let port = cli.options.port or "8080"
|
|
1771
|
+
let host = cli.options.host or "0.0.0.0"
|
|
1772
|
+
server(port) {
|
|
1773
|
+
get "/" (req, res) { res.json({ host, port }) }
|
|
1774
|
+
}
|
|
709
1775
|
```
|
|
710
1776
|
|
|
711
|
-
### `FuncDef`
|
|
712
1777
|
```nova
|
|
713
|
-
|
|
714
|
-
|
|
1778
|
+
// novac build.nova src/main.nova --minify --output dist/app.js
|
|
1779
|
+
let inputFile = cli.args[0]
|
|
1780
|
+
let minify = cli.options.minify or false
|
|
1781
|
+
let output = cli.options.output or "out.js"
|
|
1782
|
+
```
|
|
715
1783
|
|
|
716
|
-
|
|
717
|
-
|
|
1784
|
+
```nova
|
|
1785
|
+
// novac deploy.nova @production +cache
|
|
1786
|
+
if (cli.addrs.production) {
|
|
1787
|
+
core.print("Deploying to production")
|
|
1788
|
+
}
|
|
1789
|
+
if (cli.additions.cache) {
|
|
1790
|
+
core.print("Cache warming enabled")
|
|
1791
|
+
}
|
|
718
1792
|
```
|
|
719
1793
|
|
|
720
|
-
|
|
1794
|
+
---
|
|
1795
|
+
|
|
1796
|
+
## Threads
|
|
721
1797
|
|
|
722
1798
|
```nova
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
1799
|
+
func worker() => {
|
|
1800
|
+
give heavyComputation()
|
|
1801
|
+
}
|
|
1802
|
+
|
|
1803
|
+
let t = Thread(worker)
|
|
1804
|
+
t.start()
|
|
1805
|
+
t.send("message")
|
|
1806
|
+
t.on_message(msg => { core.print(msg) })
|
|
1807
|
+
let result = t.join()
|
|
1808
|
+
```
|
|
1809
|
+
|
|
1810
|
+
| Method / Property | Description |
|
|
1811
|
+
|-------------------|-------------|
|
|
1812
|
+
| `.start()` | Spawn the worker thread |
|
|
1813
|
+
| `.join()` | Block until done; applies scope mutations; returns result |
|
|
1814
|
+
| `.send(value)` | Post message to worker |
|
|
1815
|
+
| `.on_message(fn)` | Handler for messages from worker |
|
|
1816
|
+
| `.result` | Final return value |
|
|
1817
|
+
| `.error` | Error string if worker threw |
|
|
1818
|
+
| `.done` | Boolean: completed |
|
|
1819
|
+
|
|
1820
|
+
Scope snapshot: user-defined variables serialized and sent. Functions serialized via `toString()`. Worker can write back via `thread.set(name, val)` — applied atomically on `.join()`.
|
|
1821
|
+
|
|
729
1822
|
|
|
730
|
-
|
|
731
|
-
let s = Stack(1, 2, 3);
|
|
732
|
-
s.push(4);
|
|
733
|
-
core.print(s.pop()); // 4
|
|
734
|
-
core.print(s.peek()); // 3
|
|
735
|
-
|
|
736
|
-
// Queue (FIFO)
|
|
737
|
-
let q = Queue();
|
|
738
|
-
q.enqueue("a"); q.enqueue("b");
|
|
739
|
-
core.print(q.dequeue()); // a
|
|
740
|
-
|
|
741
|
-
// LinkedList
|
|
742
|
-
let ll = LinkedList();
|
|
743
|
-
ll.push(1).push(2).push(3);
|
|
744
|
-
core.print(ll.size); // 3
|
|
745
|
-
core.print(ll.shift()); // 1
|
|
746
|
-
|
|
747
|
-
// Timer
|
|
748
|
-
let t = Timer();
|
|
749
|
-
t.start();
|
|
750
|
-
// ... work ...
|
|
751
|
-
core.print(t.elapsed); // ms elapsed
|
|
752
|
-
t.lap(); // record a lap
|
|
753
|
-
|
|
754
|
-
// State Machine
|
|
755
|
-
let sm = State("idle");
|
|
756
|
-
sm.add("idle", "start", "running")
|
|
757
|
-
.add("running", "pause", "paused")
|
|
758
|
-
.add("paused", "resume", "running")
|
|
759
|
-
.add("running", "stop", "idle");
|
|
760
|
-
sm.onEnter("running", s => core.print(f"entered {s}"));
|
|
761
|
-
sm.dispatch("start");
|
|
762
|
-
core.print(sm.current); // "running"
|
|
763
|
-
```
|
|
764
|
-
|
|
765
|
-
### Reactive Primitives
|
|
766
|
-
|
|
767
|
-
```nova
|
|
768
|
-
// Observable — reactive value with subscribers
|
|
769
|
-
let count = Observable(0);
|
|
770
|
-
count.subscribe((newVal, oldVal) => core.print(f"{oldVal} → {newVal}"));
|
|
771
|
-
count.value = 42; // triggers subscriber
|
|
772
|
-
|
|
773
|
-
// Derived observable
|
|
774
|
-
let doubled = count.pipe(x => x * 2);
|
|
775
|
-
count.value = 10; // doubled.value = 20 automatically
|
|
776
|
-
|
|
777
|
-
// Signal — simpler reactive primitive
|
|
778
|
-
let x = Signal(5);
|
|
779
|
-
let y = x.derive(v => v * 3);
|
|
780
|
-
core.print(y.value); // 15
|
|
781
|
-
x.value = 10;
|
|
782
|
-
core.print(y.value); // 30
|
|
783
|
-
|
|
784
|
-
x.effect(v => core.print(f"x changed to {v}"));
|
|
785
|
-
```
|
|
786
|
-
|
|
787
|
-
### Utilities
|
|
788
|
-
|
|
789
|
-
```nova
|
|
790
|
-
// Validator
|
|
791
|
-
let v = Validator()
|
|
792
|
-
.required()
|
|
793
|
-
.type("number")
|
|
794
|
-
.min(0).max(100)
|
|
795
|
-
.custom(x => x % 2 == 0, "must be even");
|
|
796
|
-
|
|
797
|
-
let result = v.validate(42);
|
|
798
|
-
core.print(result.valid); // true
|
|
799
|
-
core.print(result.errors); // []
|
|
800
|
-
|
|
801
|
-
// Special built-in validators
|
|
802
|
-
let emailV = Validator().email();
|
|
803
|
-
|
|
804
|
-
// Memo — memoized function
|
|
805
|
-
let fib = Memo(n => n <= 1 ? n : fib.call(n-1) + fib.call(n-2));
|
|
806
|
-
core.print(fib.call(10)); // 55
|
|
807
|
-
core.print(fib.stats.hits); // cache hits
|
|
808
|
-
|
|
809
|
-
// Lazy — deferred evaluation
|
|
810
|
-
let heavy = Lazy(() => expensiveComputation());
|
|
811
|
-
// Not evaluated until:
|
|
812
|
-
core.print(heavy.value); // computed once and cached
|
|
813
|
-
core.print(heavy.value); // served from cache
|
|
814
|
-
|
|
815
|
-
// DataStream — lazy collection transformations
|
|
816
|
-
let ds = DataStream(hugeArray)
|
|
817
|
-
.filter(x => x.active)
|
|
818
|
-
.map(x => x.value)
|
|
819
|
-
.distinct()
|
|
820
|
-
.sort()
|
|
821
|
-
.take(10)
|
|
822
|
-
.collect();
|
|
823
|
-
|
|
824
|
-
// Transformer — bidirectional value mapping
|
|
825
|
-
let t = Transformer().encode(v => v * 2).decode(v => v / 2);
|
|
826
|
-
core.print(t.to(5)); // 10
|
|
827
|
-
core.print(t.from(10)); // 5
|
|
828
|
-
|
|
829
|
-
// Built-in transformers
|
|
830
|
-
let json = TransformerJSON();
|
|
831
|
-
let b64 = TransformerBase64();
|
|
832
|
-
|
|
833
|
-
// Router — pattern dispatcher
|
|
834
|
-
let r = Router();
|
|
835
|
-
r.on("/users/(.*)", id => handleUser(id));
|
|
836
|
-
r.on("/posts/(.*)/(.*)$", (id, action) => handlePost(id, action));
|
|
837
|
-
r.default(path => notFound(path));
|
|
838
|
-
r.dispatch("/users/42");
|
|
839
|
-
|
|
840
|
-
// EventBus — standalone pub/sub (separate from Nova event system)
|
|
841
|
-
let bus = EventBus();
|
|
842
|
-
bus.on("data", v => process(v));
|
|
843
|
-
bus.once("ready", () => init());
|
|
844
|
-
bus.emit("data", payload);
|
|
845
|
-
bus.off("data", handler);
|
|
846
|
-
```
|
|
1823
|
+
Read also: NVML readme (./kits/kitnovacweb/README.md)
|