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/novac/README.md
ADDED
|
@@ -0,0 +1,1823 @@
|
|
|
1
|
+
# novac Language Reference
|
|
2
|
+
|
|
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
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
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)
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Comments
|
|
38
|
+
|
|
39
|
+
```nova
|
|
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
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Preprocessor Directives
|
|
50
|
+
|
|
51
|
+
```nova
|
|
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
|
+
}
|
|
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
|
+
```
|
|
141
|
+
|
|
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' }
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Destructuring
|
|
155
|
+
|
|
156
|
+
```nova
|
|
157
|
+
let { a, b } = obj
|
|
158
|
+
let { a: renamed, b: other = "default" } = obj
|
|
159
|
+
let [first, second] = arr
|
|
160
|
+
let [head, ...tail] = arr
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Smart Variable Modifiers
|
|
164
|
+
|
|
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
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
```nova
|
|
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
|
|
250
|
+
}
|
|
251
|
+
let v = Vec2({ x: 3, y: 4 })
|
|
252
|
+
v.x // 3
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Interface
|
|
256
|
+
|
|
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 { }
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### Enum
|
|
267
|
+
|
|
268
|
+
```nova
|
|
269
|
+
enum Status { Active, Inactive, Pending }
|
|
270
|
+
enum Shape {
|
|
271
|
+
Circle(int),
|
|
272
|
+
Rect(int, int),
|
|
273
|
+
Point = 0
|
|
274
|
+
}
|
|
275
|
+
let s = Status.Active
|
|
276
|
+
s.__variant__ // "Active"
|
|
277
|
+
s.__enum_type__ // "Status"
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Trait & Impl
|
|
281
|
+
|
|
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 { }
|
|
290
|
+
```
|
|
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
|
+
|
|
438
|
+
---
|
|
439
|
+
|
|
440
|
+
## Strings & F-Strings
|
|
441
|
+
|
|
442
|
+
```nova
|
|
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(', ')}"
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
---
|
|
454
|
+
|
|
455
|
+
## Control Flow
|
|
456
|
+
|
|
457
|
+
### If / Else
|
|
458
|
+
|
|
459
|
+
```nova
|
|
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
|
|
467
|
+
|
|
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
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
### While / Do-While
|
|
475
|
+
|
|
476
|
+
```nova
|
|
477
|
+
while (cond) { }
|
|
478
|
+
do { } while (cond)
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
### For
|
|
482
|
+
|
|
483
|
+
```nova
|
|
484
|
+
for (let i = 0; i < 10; i++) { }
|
|
485
|
+
for (let item of array) { }
|
|
486
|
+
for (let key in object) { }
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
### Each
|
|
490
|
+
|
|
491
|
+
```nova
|
|
492
|
+
each item of array { }
|
|
493
|
+
each item, index of array { }
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
### Switch / Case
|
|
497
|
+
|
|
498
|
+
```nova
|
|
499
|
+
switch (value) {
|
|
500
|
+
case 1: core.print("one"); break;
|
|
501
|
+
default: core.print("other"); break;
|
|
502
|
+
}
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
### Match
|
|
506
|
+
|
|
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
|
+
}
|
|
515
|
+
```
|
|
516
|
+
|
|
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
|
+
|
|
529
|
+
```nova
|
|
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
|
|
538
|
+
|
|
539
|
+
```nova
|
|
540
|
+
when cond do { } // runs body once if cond is truthy
|
|
541
|
+
when cond then { } // same
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
### Where (scoped bindings)
|
|
545
|
+
|
|
546
|
+
```nova
|
|
547
|
+
where (base = 100, rate = 0.15) {
|
|
548
|
+
let tax = base * rate
|
|
549
|
+
}
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
### With
|
|
553
|
+
|
|
554
|
+
```nova
|
|
555
|
+
with (object) {
|
|
556
|
+
// object properties brought into scope
|
|
557
|
+
}
|
|
558
|
+
with option featureFlag {
|
|
559
|
+
// body runs with flag set; removed after block
|
|
560
|
+
}
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
### Loop (Classic iteration)
|
|
564
|
+
|
|
565
|
+
```nova
|
|
566
|
+
loop item in iterable { }
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
### Foreach (Classic key-value)
|
|
570
|
+
|
|
571
|
+
```nova
|
|
572
|
+
foreach(collection)(key, value) { }
|
|
573
|
+
foreach(collection)(key, value, length) { } // third var = total length
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
### Wait (sync sleep)
|
|
577
|
+
|
|
578
|
+
```nova
|
|
579
|
+
wait(1000) // blocks for 1000ms (Atomics.wait, fallback: child process)
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
### Time Block
|
|
583
|
+
|
|
584
|
+
```nova
|
|
585
|
+
time {
|
|
586
|
+
// times this block; prints elapsed ms on completion
|
|
587
|
+
}
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
---
|
|
591
|
+
|
|
592
|
+
## Functions
|
|
593
|
+
|
|
594
|
+
### Named Functions
|
|
595
|
+
|
|
596
|
+
```nova
|
|
597
|
+
func add(a, b) => {
|
|
598
|
+
give a + b
|
|
599
|
+
}
|
|
600
|
+
function greet(name) {
|
|
601
|
+
return f"Hello {name}"
|
|
602
|
+
}
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
### Function Modifiers
|
|
606
|
+
|
|
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
|
|
657
|
+
|
|
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
|
+
```
|
|
664
|
+
|
|
665
|
+
### Arrow Functions
|
|
666
|
+
|
|
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
|
+
```
|
|
678
|
+
|
|
679
|
+
### Block functions:
|
|
680
|
+
these auto call on reference, and use the returned value
|
|
681
|
+
```nova
|
|
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')
|
|
688
|
+
```
|
|
689
|
+
|
|
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
|
+
```
|
|
702
|
+
|
|
703
|
+
### Pipe Operator
|
|
704
|
+
|
|
705
|
+
```nova
|
|
706
|
+
let result = 5 |> double |> addOne
|
|
707
|
+
```
|
|
708
|
+
|
|
709
|
+
---
|
|
710
|
+
|
|
711
|
+
## Classes
|
|
712
|
+
|
|
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
|
|
728
|
+
|
|
729
|
+
```nova
|
|
730
|
+
class Box {
|
|
731
|
+
_val: 0
|
|
732
|
+
get value() { give this._val; }
|
|
733
|
+
set value(v) { this._val = v; }
|
|
734
|
+
}
|
|
735
|
+
```
|
|
736
|
+
|
|
737
|
+
### Decorators
|
|
738
|
+
|
|
739
|
+
```nova
|
|
740
|
+
@logged
|
|
741
|
+
@deprecated("use newFn")
|
|
742
|
+
class OldClass {
|
|
743
|
+
@readonly
|
|
744
|
+
name: "old"
|
|
745
|
+
}
|
|
746
|
+
```
|
|
747
|
+
|
|
748
|
+
---
|
|
749
|
+
|
|
750
|
+
## Pattern Matching
|
|
751
|
+
|
|
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
|
+
}
|
|
760
|
+
```
|
|
761
|
+
|
|
762
|
+
---
|
|
763
|
+
|
|
764
|
+
## Events
|
|
765
|
+
|
|
766
|
+
```nova
|
|
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" () { }
|
|
776
|
+
```
|
|
777
|
+
|
|
778
|
+
---
|
|
779
|
+
|
|
780
|
+
## Error Handling
|
|
781
|
+
|
|
782
|
+
```nova
|
|
783
|
+
try {
|
|
784
|
+
riskyOp()
|
|
785
|
+
} catch (err) {
|
|
786
|
+
core.print(f"caught: {err}")
|
|
787
|
+
} finally {
|
|
788
|
+
cleanup()
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
try { riskyOp() } catch { } // no binding — catch without name
|
|
792
|
+
|
|
793
|
+
throw "plain string"
|
|
794
|
+
throw new Error("typed")
|
|
795
|
+
|
|
796
|
+
assert condition
|
|
797
|
+
assert condition, "failure message"
|
|
798
|
+
|
|
799
|
+
expt "expectedOutput" from {
|
|
800
|
+
core.print("expectedOutput")
|
|
801
|
+
}
|
|
802
|
+
```
|
|
803
|
+
|
|
804
|
+
---
|
|
805
|
+
|
|
806
|
+
## Modules & Namespaces
|
|
807
|
+
|
|
808
|
+
### Import
|
|
809
|
+
|
|
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
|
+
```
|
|
825
|
+
|
|
826
|
+
### Namespace
|
|
827
|
+
|
|
828
|
+
```nova
|
|
829
|
+
namespace Math {
|
|
830
|
+
func add(a, b) => { give a + b }
|
|
831
|
+
}
|
|
832
|
+
Math::add(1, 2)
|
|
833
|
+
using namespace Math // bring all members into scope
|
|
834
|
+
```
|
|
835
|
+
|
|
836
|
+
### Using / Unuse
|
|
837
|
+
|
|
838
|
+
```nova
|
|
839
|
+
using featureFlag
|
|
840
|
+
using namespace MyNS
|
|
841
|
+
unuse featureFlag
|
|
842
|
+
```
|
|
843
|
+
|
|
844
|
+
### Environment Variable
|
|
845
|
+
|
|
846
|
+
```nova
|
|
847
|
+
env VAR_NAME // reads process.env.VAR_NAME; throws if undefined
|
|
848
|
+
```
|
|
849
|
+
|
|
850
|
+
---
|
|
851
|
+
|
|
852
|
+
## HTTP & Networking
|
|
853
|
+
|
|
854
|
+
### First-Class HTTP Verbs
|
|
855
|
+
|
|
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.
|
|
868
|
+
|
|
869
|
+
### Fetch
|
|
870
|
+
|
|
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
|
|
875
|
+
```
|
|
876
|
+
|
|
877
|
+
### Server Declaration
|
|
878
|
+
|
|
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
|
+
```
|
|
896
|
+
|
|
897
|
+
---
|
|
898
|
+
|
|
899
|
+
## @classic — Classic Compatibility Block
|
|
900
|
+
|
|
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.
|
|
902
|
+
|
|
903
|
+
```nova
|
|
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
|
|
913
|
+
}
|
|
914
|
+
```
|
|
915
|
+
|
|
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.
|
|
924
|
+
|
|
925
|
+
```nova
|
|
926
|
+
func migrate() => {
|
|
927
|
+
@classic {
|
|
928
|
+
backup session = currentSession
|
|
929
|
+
temp session = "migration" => {
|
|
930
|
+
runMigration()
|
|
931
|
+
}
|
|
932
|
+
retrieve session
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
```
|
|
936
|
+
|
|
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 |
|
|
1205
|
+
```
|
|
1206
|
+
|
|
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)`
|
|
1226
|
+
|
|
1227
|
+
```nova
|
|
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)`
|
|
1245
|
+
|
|
1246
|
+
```nova
|
|
1247
|
+
WhileLoop({}).cond(() => n < 32).do(() => { n *= 2 }).maxIter(100).run()
|
|
1248
|
+
```
|
|
1249
|
+
|
|
1250
|
+
### `IfBlock(opts)`
|
|
1251
|
+
|
|
1252
|
+
```nova
|
|
1253
|
+
IfBlock({ cond: score >= 90, then: () => "A" })
|
|
1254
|
+
.elseIf(score >= 80, () => "B").else(() => "F").run()
|
|
1255
|
+
```
|
|
1256
|
+
|
|
1257
|
+
### `MatchBlock(subject)`
|
|
1258
|
+
|
|
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
|
+
```
|
|
1268
|
+
|
|
1269
|
+
### `TryCatch()`
|
|
1270
|
+
|
|
1271
|
+
```nova
|
|
1272
|
+
TryCatch().try(() => { throw "oops" }).catch(e => core.print(e)).finally(() => {}).run()
|
|
1273
|
+
```
|
|
1274
|
+
|
|
1275
|
+
### `Pipeline(initial)`
|
|
1276
|
+
|
|
1277
|
+
```nova
|
|
1278
|
+
Pipeline([1,2,3,4,5]).filter(x => x % 2 == 0).map(x => x*x).take(2).collect()
|
|
1279
|
+
```
|
|
1280
|
+
|
|
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)`
|
|
1292
|
+
|
|
1293
|
+
```nova
|
|
1294
|
+
FuncDef({ args: ["a", "b"], body: (a, b) => a + b }).named("add").call(10, 32)
|
|
1295
|
+
```
|
|
1296
|
+
|
|
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
|
|
1303
|
+
```
|
|
1304
|
+
|
|
1305
|
+
### `Counter(initial, step)`
|
|
1306
|
+
|
|
1307
|
+
```nova
|
|
1308
|
+
let c = Counter(0); c.increment(5); c.decrement(2); c.clamp(0, 100); c.value
|
|
1309
|
+
```
|
|
1310
|
+
|
|
1311
|
+
### `Stack()` / `Queue()` / `LinkedList()`
|
|
1312
|
+
|
|
1313
|
+
```nova
|
|
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
|
+
```
|
|
1318
|
+
|
|
1319
|
+
### `State(initial)`
|
|
1320
|
+
|
|
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
|
+
```
|
|
1328
|
+
|
|
1329
|
+
### `Observable(initial)` / `Signal(initial)`
|
|
1330
|
+
|
|
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()`
|
|
1344
|
+
|
|
1345
|
+
```nova
|
|
1346
|
+
Validator().required().type("number").min(0).max(100).validate(50)
|
|
1347
|
+
// { valid: true, errors: [], value: 50 }
|
|
1348
|
+
```
|
|
1349
|
+
|
|
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()`
|
|
1372
|
+
|
|
1373
|
+
```nova
|
|
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_()
|
|
1377
|
+
```
|
|
1378
|
+
|
|
1379
|
+
### `Router()`
|
|
1380
|
+
|
|
1381
|
+
```nova
|
|
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"
|
|
1385
|
+
```
|
|
1386
|
+
|
|
1387
|
+
### `EventBus()`
|
|
1388
|
+
|
|
1389
|
+
```nova
|
|
1390
|
+
let bus = EventBus()
|
|
1391
|
+
bus.on("data", v => {}).once("ready", () => {}).off("data", handler)
|
|
1392
|
+
bus.emit("data", 42); bus.events()
|
|
1393
|
+
```
|
|
1394
|
+
|
|
1395
|
+
### `Memo(fn, keyFn?)` / `Lazy(fn)`
|
|
1396
|
+
|
|
1397
|
+
```nova
|
|
1398
|
+
let m = Memo(x => x * x * x)
|
|
1399
|
+
m.call(5); m.stats; m.clear(); m.invalidate(5)
|
|
1400
|
+
|
|
1401
|
+
let lazy = Lazy(() => expensiveOp())
|
|
1402
|
+
lazy.value; lazy.reset(); lazy.map(fn)
|
|
1403
|
+
```
|
|
1404
|
+
|
|
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`
|
|
1437
|
+
|
|
1438
|
+
```nova
|
|
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)
|
|
1442
|
+
```
|
|
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` |
|
|
1465
|
+
|
|
1466
|
+
---
|
|
1467
|
+
|
|
1468
|
+
## Standard Built-ins (`bstd` / `import_builtin`)
|
|
1469
|
+
|
|
1470
|
+
### `Air`
|
|
1471
|
+
|
|
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):
|
|
1477
|
+
|
|
1478
|
+
```nova
|
|
1479
|
+
import_builtin Chalk
|
|
1480
|
+
core.print(Chalk.red("error"))
|
|
1481
|
+
core.print(Chalk.bold.green("success"))
|
|
1482
|
+
```
|
|
1483
|
+
|
|
1484
|
+
### `History`
|
|
1485
|
+
|
|
1486
|
+
File-backed input history stored as `.184.<name>`:
|
|
1487
|
+
|
|
1488
|
+
`getKey(name)` `exists(key)` `createHistory(key)` `appendHistory(key, item, mode?, index?)` `readHistory(key)` `rawSetHistory(key, array)` `rawGetHistory(key)` `clearHistory(key)`
|
|
1489
|
+
|
|
1490
|
+
### `Input`
|
|
1491
|
+
|
|
1492
|
+
Synchronous terminal input with full line-editing:
|
|
1493
|
+
|
|
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" })
|
|
1501
|
+
```
|
|
1502
|
+
|
|
1503
|
+
Features: cursor, history `↑↓`, backspace, delete, tab completion, Ctrl+C, password masking.
|
|
1504
|
+
|
|
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`
|
|
1516
|
+
|
|
1517
|
+
### `ConfigFile`
|
|
1518
|
+
|
|
1519
|
+
```nova
|
|
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
|
+
```
|
|
1527
|
+
|
|
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()
|
|
1540
|
+
```
|
|
1541
|
+
|
|
1542
|
+
### `Crypto`
|
|
1543
|
+
|
|
1544
|
+
```nova
|
|
1545
|
+
import_builtin Crypto
|
|
1546
|
+
Crypto.hash("data") // SHA-256 hex
|
|
1547
|
+
Crypto.hash("data", "sha512") // any Node.js crypto algo
|
|
1548
|
+
```
|
|
1549
|
+
|
|
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
|
+
|
|
1564
|
+
```nova
|
|
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:
|
|
1575
|
+
|
|
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
|
|
1607
|
+
```
|
|
1608
|
+
|
|
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
|
+
|
|
1631
|
+
```nova
|
|
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
|
|
1674
|
+
```
|
|
1675
|
+
|
|
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
|
+
|
|
1746
|
+
```nova
|
|
1747
|
+
// novac myapp.nova hello world --port 8080 --debug @prod +cache
|
|
1748
|
+
|
|
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
|
|
1754
|
+
```
|
|
1755
|
+
|
|
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
|
+
|
|
1768
|
+
```nova
|
|
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
|
+
}
|
|
1775
|
+
```
|
|
1776
|
+
|
|
1777
|
+
```nova
|
|
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
|
+
```
|
|
1783
|
+
|
|
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
|
+
}
|
|
1792
|
+
```
|
|
1793
|
+
|
|
1794
|
+
---
|
|
1795
|
+
|
|
1796
|
+
## Threads
|
|
1797
|
+
|
|
1798
|
+
```nova
|
|
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
|
+
|
|
1822
|
+
|
|
1823
|
+
Read also: NVML readme (./kits/kitnovacweb/README.md)
|