nebulara 2.0.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/Compiler/nbs-bootstrap.c +2229 -0
- package/Compiler/nbs_cli.c +1553 -0
- package/Compiler/neb-cli.exe +0 -0
- package/Compiler/neb-codegen.c +287 -0
- package/Compiler/neb-ffi.c +303 -0
- package/Compiler/neb-ir.c +307 -0
- package/Compiler/neb-knowledge.c +203 -0
- package/Compiler/neb-pipeline.c +787 -0
- package/Compiler/neb-semantic.c +261 -0
- package/Compiler/nebulara.exe +0 -0
- package/README.md +258 -0
- package/SPEC.md +267 -0
- package/bin/neb.js +36 -0
- package/build/neb-cli.exe +0 -0
- package/build/neb-codegen.exe +0 -0
- package/build/neb-ffi.exe +0 -0
- package/build/neb-knowledge.exe +0 -0
- package/build/neb-pipeline.exe +0 -0
- package/build/nebulara.exe +0 -0
- package/dist/index.js +131 -0
- package/package.json +39 -0
- package/std/collections.nbs +72 -0
- package/std/json.nbs +15 -0
- package/std/kanban.nbs +122 -0
- package/std/math.nbs +52 -0
- package/std/net.nbs +22 -0
- package/std/primitives.nbs +30 -0
- package/std/string.nbs +71 -0
- package/std/time.nbs +15 -0
- package/test/broken.nbs +2 -0
- package/test/hello.nbs +6 -0
- package/test/test-arrays.nbs +22 -0
- package/test/test-charat.nbs +7 -0
- package/test/test-cont-debug.nbs +8 -0
- package/test/test-cont-min.nbs +7 -0
- package/test/test-cont-parens.nbs +7 -0
- package/test/test-cont2.nbs +7 -0
- package/test/test-cont3.nbs +7 -0
- package/test/test-control.nbs +18 -0
- package/test/test-functions.nbs +13 -0
- package/test/test-loops.nbs +17 -0
- package/test/test-mod-for.nbs +6 -0
- package/test/test-mod.nbs +5 -0
- package/test/test-new-features.nbs +39 -0
- package/test/test-recursion.nbs +23 -0
- package/test/test-runtime.nbs +8 -0
- package/test/test-strings.nbs +14 -0
- package/test/test-trycatch.nbs +11 -0
package/SPEC.md
ADDED
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
# Nebulara Language Specification v3.0
|
|
2
|
+
|
|
3
|
+
## File Extension
|
|
4
|
+
`.nbs` - Nebulara Source
|
|
5
|
+
|
|
6
|
+
## Comments
|
|
7
|
+
```
|
|
8
|
+
# This is a line comment
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Keywords
|
|
12
|
+
|
|
13
|
+
| Keyword | Usage | Example |
|
|
14
|
+
|---------|-------|---------|
|
|
15
|
+
| `FUNC!` | Define function | `FUNC! add(a, b):` |
|
|
16
|
+
| `END!` | Block end | `END!` |
|
|
17
|
+
| `LET` | Variable declaration | `LET x = 10` |
|
|
18
|
+
| `CONST` | Constant declaration | `CONST PI = 314` |
|
|
19
|
+
| `IF?` | Conditional | `IF? x > 10:` |
|
|
20
|
+
| `ELSE` | Else branch | `ELSE:` |
|
|
21
|
+
| `ELSEIF?` | Else-if branch | `ELSEIF? x > 5:` |
|
|
22
|
+
| `WHILE?` | While loop | `WHILE? i < 10:` |
|
|
23
|
+
| `FOR!` | For loop | `FOR! i = 1 TO 10:` |
|
|
24
|
+
| `TO` | FOR loop range | `FOR! i = 1 TO 10:` |
|
|
25
|
+
| `STEP` | FOR loop step | `FOR! i = 0 TO 20 STEP 5:` |
|
|
26
|
+
| `RETURN` | Return value | `RETURN a + b` |
|
|
27
|
+
| `BREAK` | Exit loop | `BREAK` |
|
|
28
|
+
| `CONTINUE` | Skip iteration | `CONTINUE` |
|
|
29
|
+
| `TRY` | Try block | `TRY:` |
|
|
30
|
+
| `CATCH` | Catch block | `CATCH err:` |
|
|
31
|
+
| `THROW` | Throw exception | `THROW "error"` |
|
|
32
|
+
| `AND` | Logical AND | `IF? a AND b:` |
|
|
33
|
+
| `OR` | Logical OR | `IF? a OR b:` |
|
|
34
|
+
| `NOT` | Logical NOT | `IF? NOT done:` |
|
|
35
|
+
| `TRUE` | Boolean true | `LET x = TRUE` |
|
|
36
|
+
| `FALSE` | Boolean false | `LET x = FALSE` |
|
|
37
|
+
| `NULL` | Null value | `IF? x == NULL:` |
|
|
38
|
+
|
|
39
|
+
## Types
|
|
40
|
+
|
|
41
|
+
| Type | Description | Example |
|
|
42
|
+
|------|-------------|---------|
|
|
43
|
+
| Int | 64-bit signed integer | `42`, `-7` |
|
|
44
|
+
| String | UTF-8 text | `"hello"` |
|
|
45
|
+
| Bool | Boolean | `TRUE`, `FALSE` |
|
|
46
|
+
| Array | Dynamic list | `[1, 2, 3]` |
|
|
47
|
+
| Null | Absence of value | `NULL` |
|
|
48
|
+
| Func | Function reference | `FUNC! name():` |
|
|
49
|
+
|
|
50
|
+
## Syntax
|
|
51
|
+
|
|
52
|
+
### Variable Declaration
|
|
53
|
+
```
|
|
54
|
+
LET x = 10
|
|
55
|
+
LET name = "Nebulara"
|
|
56
|
+
LET arr = [1, 2, 3]
|
|
57
|
+
x = 20 # reassignment (no LET)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Function Definition
|
|
61
|
+
```
|
|
62
|
+
FUNC! add(a, b):
|
|
63
|
+
RETURN a + b
|
|
64
|
+
END!
|
|
65
|
+
|
|
66
|
+
FUNC! greet(name):
|
|
67
|
+
PRINT "Hello " + name
|
|
68
|
+
END!
|
|
69
|
+
|
|
70
|
+
FUNC! noArgs():
|
|
71
|
+
PRINT "no parameters"
|
|
72
|
+
END!
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Function Call
|
|
76
|
+
```
|
|
77
|
+
PRINT add(3, 4) # prints 7
|
|
78
|
+
greet("World") # prints "Hello World"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Control Flow
|
|
82
|
+
|
|
83
|
+
#### If/Else
|
|
84
|
+
```
|
|
85
|
+
IF? x > 10:
|
|
86
|
+
PRINT "big"
|
|
87
|
+
ELSEIF? x > 5:
|
|
88
|
+
PRINT "medium"
|
|
89
|
+
ELSE:
|
|
90
|
+
PRINT "small"
|
|
91
|
+
END!
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
#### While Loop
|
|
95
|
+
```
|
|
96
|
+
LET i = 1
|
|
97
|
+
WHILE? i <= 5:
|
|
98
|
+
PRINT i
|
|
99
|
+
i = i + 1
|
|
100
|
+
END!
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
#### For Loop
|
|
104
|
+
```
|
|
105
|
+
FOR! i = 1 TO 5:
|
|
106
|
+
PRINT i
|
|
107
|
+
END!
|
|
108
|
+
|
|
109
|
+
# With STEP
|
|
110
|
+
FOR! i = 0 TO 20 STEP 5:
|
|
111
|
+
PRINT i
|
|
112
|
+
END!
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
#### Try/Catch/Throw
|
|
116
|
+
```
|
|
117
|
+
TRY:
|
|
118
|
+
LET x = TO_NUMBER("not a number")
|
|
119
|
+
CATCH err:
|
|
120
|
+
PRINT "Error: " + err
|
|
121
|
+
END!
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
`THROW` raises an exception with a value (typically a string). If no `TRY` block is active, the program terminates with an uncaught exception error.
|
|
125
|
+
|
|
126
|
+
### Operators
|
|
127
|
+
|
|
128
|
+
#### Arithmetic
|
|
129
|
+
```
|
|
130
|
+
+ # addition / string concatenation
|
|
131
|
+
- # subtraction
|
|
132
|
+
* # multiplication
|
|
133
|
+
/ # division
|
|
134
|
+
% # modulo
|
|
135
|
+
- # unary negation
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
#### Bitwise
|
|
139
|
+
```
|
|
140
|
+
& # bitwise AND: 5 & 3 → 1
|
|
141
|
+
| # bitwise OR: 5 | 3 → 7
|
|
142
|
+
<< # left shift: 1 << 3 → 8
|
|
143
|
+
>> # right shift: 8 >> 2 → 2
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
#### Comparison
|
|
147
|
+
```
|
|
148
|
+
== # equal
|
|
149
|
+
!= # not equal
|
|
150
|
+
< # less than
|
|
151
|
+
> # greater than
|
|
152
|
+
<= # less or equal
|
|
153
|
+
>= # greater or equal
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
#### Logical
|
|
157
|
+
```
|
|
158
|
+
AND # logical and
|
|
159
|
+
OR # logical or
|
|
160
|
+
NOT # logical not
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
#### String
|
|
164
|
+
```
|
|
165
|
+
+ # concatenation: "hello" + " " + "world" → "hello world"
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Arrays
|
|
169
|
+
```
|
|
170
|
+
LET arr = [10, 20, 30]
|
|
171
|
+
PRINT arr[0] # 10
|
|
172
|
+
arr[1] = 99 # mutation: arr is now [10, 99, 30]
|
|
173
|
+
PRINT LEN(arr) # 3
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Arrays support index-based assignment (`arr[i] = value`) to mutate elements in place.
|
|
177
|
+
|
|
178
|
+
### Built-in Functions
|
|
179
|
+
|
|
180
|
+
#### Output & Input
|
|
181
|
+
|
|
182
|
+
| Function | Signature | Description |
|
|
183
|
+
|----------|-----------|-------------|
|
|
184
|
+
| `PRINT` | `PRINT(value)` | Print value to stdout with newline. Accepts any type. |
|
|
185
|
+
|
|
186
|
+
#### String Functions
|
|
187
|
+
|
|
188
|
+
| Function | Signature | Description |
|
|
189
|
+
|----------|-----------|-------------|
|
|
190
|
+
| `LEN` | `LEN(value)` | Returns the length of a string (byte count) or array (element count). Returns `0` for other types. |
|
|
191
|
+
| `TYPEOF` | `TYPEOF(value)` | Returns the type name as a string: `"int"`, `"string"`, `"bool"`, `"array"`, `"null"`, `"func"` |
|
|
192
|
+
| `TO_STRING` | `TO_STRING(value)` | Convert value to its string representation. |
|
|
193
|
+
| `TO_NUMBER` | `TO_NUMBER(value)` | Parse a string as an integer (`atoll`). Returns `0` for non-parseable strings. Returns the value unchanged if already an int. |
|
|
194
|
+
| `CHAR_AT` | `CHAR_AT(str, index)` | Returns the single-character string at `index`. Returns `NULL` if index is out of bounds. |
|
|
195
|
+
| `SUBSTR` | `SUBSTR(str, start, length)` | Returns a substring starting at `start` for `length` characters. Clamps to string bounds. |
|
|
196
|
+
| `TRIM` | `TRIM(str)` | Removes leading and trailing whitespace (spaces, tabs, newlines, carriage returns). |
|
|
197
|
+
| `TO_UPPER` | `TO_UPPER(str)` | Returns an uppercase copy of the string. Returns `""` for non-strings. |
|
|
198
|
+
| `TO_LOWER` | `TO_LOWER(str)` | Returns a lowercase copy of the string. Returns `""` for non-strings. |
|
|
199
|
+
| `CHAR` | `CHAR(code)` | Convert an integer code point to a single-character string. |
|
|
200
|
+
| `ORD` | `ORD(char)` | Convert the first character of a string to its integer code point. Returns `0` for empty strings. |
|
|
201
|
+
|
|
202
|
+
#### Math Functions
|
|
203
|
+
|
|
204
|
+
| Function | Signature | Description |
|
|
205
|
+
|----------|-----------|-------------|
|
|
206
|
+
| `ABS` | `ABS(n)` | Absolute value. Returns `0` for non-integers. |
|
|
207
|
+
| `MIN` | `MIN(a, b)` | Returns the smaller of two integers. |
|
|
208
|
+
| `MAX` | `MAX(a, b)` | Returns the larger of two integers. |
|
|
209
|
+
| `SQRT` | `SQRT(n)` | Integer square root (truncated). |
|
|
210
|
+
| `POW` | `POW(base, exp)` | Integer power: `base` raised to `exp`. |
|
|
211
|
+
| `FLOOR` | `FLOOR(n)` | Floor (no-op on integers, passes value through). |
|
|
212
|
+
| `CEIL` | `CEIL(n)` | Ceiling (no-op on integers, passes value through). |
|
|
213
|
+
| `ROUND` | `ROUND(n)` | Round (no-op on integers, passes value through). |
|
|
214
|
+
| `RANDOM` | `RANDOM()` | Returns a random integer from `0` to `99`. |
|
|
215
|
+
|
|
216
|
+
#### Array Functions
|
|
217
|
+
|
|
218
|
+
| Function | Signature | Description |
|
|
219
|
+
|----------|-----------|-------------|
|
|
220
|
+
| `PUSH` | `PUSH(arr, value)` | Appends `value` to the end of `arr`. Returns the modified array. |
|
|
221
|
+
| `POP` | `POP(arr)` | Removes and returns the last element. Returns `NULL` if the array is empty. |
|
|
222
|
+
|
|
223
|
+
#### System Functions
|
|
224
|
+
|
|
225
|
+
| Function | Signature | Description |
|
|
226
|
+
|----------|-----------|-------------|
|
|
227
|
+
| `TIME` | `TIME()` | Returns the current epoch time in seconds. |
|
|
228
|
+
| `READ_FILE` | `READ_FILE(path)` | Reads and returns the entire contents of a file as a string. Returns `NULL` if the file cannot be opened. |
|
|
229
|
+
| `WRITE_FILE` | `WRITE_FILE(path, content)` | Writes `content` to the file at `path`. Returns `TRUE` on success, `FALSE` on failure. |
|
|
230
|
+
|
|
231
|
+
## Example Programs
|
|
232
|
+
|
|
233
|
+
### Factorial
|
|
234
|
+
```
|
|
235
|
+
FUNC! factorial(n):
|
|
236
|
+
IF? n <= 1:
|
|
237
|
+
RETURN 1
|
|
238
|
+
END!
|
|
239
|
+
RETURN n * factorial(n - 1)
|
|
240
|
+
END!
|
|
241
|
+
|
|
242
|
+
PRINT factorial(5) # 120
|
|
243
|
+
PRINT factorial(10) # 3628800
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Array Mutation
|
|
247
|
+
```
|
|
248
|
+
LET arr = [1, 2, 3]
|
|
249
|
+
PUSH(arr, 4)
|
|
250
|
+
PRINT arr # [1, 2, 3, 4]
|
|
251
|
+
arr[0] = 99
|
|
252
|
+
PRINT arr # [99, 2, 3, 4]
|
|
253
|
+
PRINT POP(arr) # 4
|
|
254
|
+
PRINT arr # [99, 2, 3]
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Try/Catch
|
|
258
|
+
```
|
|
259
|
+
TRY:
|
|
260
|
+
LET result = TO_NUMBER("not a number")
|
|
261
|
+
IF? result == 0:
|
|
262
|
+
THROW "parse failed"
|
|
263
|
+
END!
|
|
264
|
+
CATCH err:
|
|
265
|
+
PRINT err
|
|
266
|
+
END!
|
|
267
|
+
```
|
package/bin/neb.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const { execFileSync } = require('child_process');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
|
|
8
|
+
const args = process.argv.slice(2);
|
|
9
|
+
const exeName = process.platform === 'win32' ? 'nebulara.exe' : 'nebulara';
|
|
10
|
+
|
|
11
|
+
// Try to find the native binary
|
|
12
|
+
function findBinary() {
|
|
13
|
+
// In installed package: bin/../build/
|
|
14
|
+
const pkgRoot = path.resolve(__dirname, '..');
|
|
15
|
+
const candidates = [
|
|
16
|
+
path.join(pkgRoot, 'build', exeName),
|
|
17
|
+
path.join(pkgRoot, exeName),
|
|
18
|
+
];
|
|
19
|
+
for (const p of candidates) {
|
|
20
|
+
if (fs.existsSync(p)) return p;
|
|
21
|
+
}
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const bin = findBinary();
|
|
26
|
+
if (!bin) {
|
|
27
|
+
console.error('Error: Nebulara binary not found. Run "npm run build" first.');
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
execFileSync(bin, args, { stdio: 'inherit' });
|
|
33
|
+
} catch (err) {
|
|
34
|
+
if (err.status !== undefined) process.exit(err.status);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @codurra/nebulara - Nebulara Programming Language Runtime
|
|
3
|
+
*
|
|
4
|
+
* Provides programmatic access to the Nebulara interpreter, transpiler, and compiler.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
const { execFileSync } = require('child_process');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const os = require('os');
|
|
13
|
+
|
|
14
|
+
const BUILD_DIR = path.join(__dirname, '..', 'build');
|
|
15
|
+
const PLATFORM = os.platform();
|
|
16
|
+
const EXTENSION = PLATFORM === 'win32' ? '.exe' : '';
|
|
17
|
+
|
|
18
|
+
const INTERPRETER = path.join(BUILD_DIR, `nebulara${EXTENSION}`);
|
|
19
|
+
const CLI = path.join(BUILD_DIR, `neb-cli${EXTENSION}`);
|
|
20
|
+
const PIPELINE = path.join(BUILD_DIR, `neb-pipeline${EXTENSION}`);
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Run a Nebulara source file
|
|
24
|
+
* @param {string} sourcePath - Path to .nbs file
|
|
25
|
+
* @param {object} options - { debug: boolean }
|
|
26
|
+
* @returns {string} stdout output
|
|
27
|
+
*/
|
|
28
|
+
function run(sourcePath, options = {}) {
|
|
29
|
+
if (!fs.existsSync(sourcePath)) throw new Error(`Source file not found: ${sourcePath}`);
|
|
30
|
+
const args = [sourcePath];
|
|
31
|
+
if (options.debug) args.unshift('-d');
|
|
32
|
+
return execFileSync(INTERPRETER, args, { encoding: 'utf8', timeout: 30000 });
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Run a Nebulara source string
|
|
37
|
+
* @param {string} source - Nebulara source code
|
|
38
|
+
* @param {object} options - { debug: boolean }
|
|
39
|
+
* @returns {string} stdout output
|
|
40
|
+
*/
|
|
41
|
+
function runString(source, options = {}) {
|
|
42
|
+
const tmpFile = path.join(os.tmpdir(), `neb_${Date.now()}.nbs`);
|
|
43
|
+
try {
|
|
44
|
+
fs.writeFileSync(tmpFile, source, 'utf8');
|
|
45
|
+
return run(tmpFile, options);
|
|
46
|
+
} finally {
|
|
47
|
+
try { fs.unlinkSync(tmpFile); } catch (e) {}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Transpile Nebulara to JavaScript
|
|
53
|
+
* @param {string} sourcePath - Path to .nbs file
|
|
54
|
+
* @returns {string} Transpiled JavaScript code
|
|
55
|
+
*/
|
|
56
|
+
function transpileToJS(sourcePath) {
|
|
57
|
+
if (!fs.existsSync(PIPELINE)) throw new Error('Pipeline binary not found. Run "npm run build" first.');
|
|
58
|
+
return execFileSync(PIPELINE, [sourcePath, '--target', 'js'], { encoding: 'utf8' });
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Transpile Nebulara to Python
|
|
63
|
+
* @param {string} sourcePath - Path to .nbs file
|
|
64
|
+
* @returns {string} Transpiled Python code
|
|
65
|
+
*/
|
|
66
|
+
function transpileToPython(sourcePath) {
|
|
67
|
+
if (!fs.existsSync(PIPELINE)) throw new Error('Pipeline binary not found. Run "npm run build" first.');
|
|
68
|
+
return execFileSync(PIPELINE, [sourcePath, '--target', 'py'], { encoding: 'utf8' });
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Check if a .nbs file parses correctly
|
|
73
|
+
* @param {string} sourcePath - Path to .nbs file
|
|
74
|
+
* @returns {{ ok: boolean, output: string }}
|
|
75
|
+
*/
|
|
76
|
+
function check(sourcePath) {
|
|
77
|
+
if (!fs.existsSync(PIPELINE)) throw new Error('Pipeline binary not found. Run "npm run build" first.');
|
|
78
|
+
try {
|
|
79
|
+
const output = execFileSync(PIPELINE, [sourcePath], { encoding: 'utf8' });
|
|
80
|
+
return { ok: true, output: output.trim() };
|
|
81
|
+
} catch (e) {
|
|
82
|
+
return { ok: false, output: (e.stderr || e.message).trim() };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Get the language specification
|
|
88
|
+
* @returns {string} SPEC.md content
|
|
89
|
+
*/
|
|
90
|
+
function getSpec() {
|
|
91
|
+
return fs.readFileSync(path.join(__dirname, '..', 'SPEC.md'), 'utf8');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Run the built-in test suite
|
|
96
|
+
* @returns {{ passed: number, failed: number, results: object[] }}
|
|
97
|
+
*/
|
|
98
|
+
function test() {
|
|
99
|
+
const testDir = path.join(__dirname, '..', 'test');
|
|
100
|
+
const results = [];
|
|
101
|
+
let passed = 0, failed = 0;
|
|
102
|
+
const testFiles = fs.readdirSync(testDir).filter(f => f.endsWith('.nbs'));
|
|
103
|
+
for (const file of testFiles) {
|
|
104
|
+
try {
|
|
105
|
+
const output = run(path.join(testDir, file));
|
|
106
|
+
results.push({ file, status: 'pass', output: output.trim() });
|
|
107
|
+
passed++;
|
|
108
|
+
} catch (e) {
|
|
109
|
+
results.push({ file, status: 'fail', error: e.message });
|
|
110
|
+
failed++;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return { passed, failed, results };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Check if the Nebulara binary is available
|
|
118
|
+
* @returns {boolean}
|
|
119
|
+
*/
|
|
120
|
+
function isAvailable() { return fs.existsSync(INTERPRETER); }
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Get the version string
|
|
124
|
+
* @returns {string}
|
|
125
|
+
*/
|
|
126
|
+
function getVersion() { return '2.0.0'; }
|
|
127
|
+
|
|
128
|
+
module.exports = {
|
|
129
|
+
run, runString, transpileToJS, transpileToPython, check, getSpec,
|
|
130
|
+
test, isAvailable, getVersion, INTERPRETER, CLI, PIPELINE, BUILD_DIR
|
|
131
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nebulara",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Nebulara - AI-native universal programming language ecosystem",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"neb": "bin/neb.js",
|
|
8
|
+
"nebulara": "bin/neb.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "node scripts/build.js",
|
|
12
|
+
"test": "node scripts/test.js",
|
|
13
|
+
"clean": "node -e \"require('fs').rmSync('build',{recursive:true,force:true})\"",
|
|
14
|
+
"prepublishOnly": "npm run build"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {},
|
|
17
|
+
"devDependencies": {},
|
|
18
|
+
"files": [
|
|
19
|
+
"bin/",
|
|
20
|
+
"dist/",
|
|
21
|
+
"build/",
|
|
22
|
+
"Compiler/",
|
|
23
|
+
"std/",
|
|
24
|
+
"test/",
|
|
25
|
+
"SPEC.md",
|
|
26
|
+
"README.md"
|
|
27
|
+
],
|
|
28
|
+
"keywords": ["compiler", "programming-language", "ai-native", "nebulara"],
|
|
29
|
+
"author": "Codurra",
|
|
30
|
+
"license": "UNLICENSED",
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/CODURRALABS/NEBULARA.git"
|
|
34
|
+
},
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=14.0.0"
|
|
37
|
+
},
|
|
38
|
+
"os": ["win32", "linux", "darwin"]
|
|
39
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Nebulara Standard Library - Collections
|
|
2
|
+
# Array and collection utilities
|
|
3
|
+
|
|
4
|
+
FUNC! find(arr, value):
|
|
5
|
+
LET i = 0
|
|
6
|
+
LET len = LEN(arr)
|
|
7
|
+
WHILE? i < len:
|
|
8
|
+
IF? arr[i] == value:
|
|
9
|
+
RETURN i
|
|
10
|
+
END!
|
|
11
|
+
i = i + 1
|
|
12
|
+
END!
|
|
13
|
+
RETURN -1
|
|
14
|
+
END!
|
|
15
|
+
|
|
16
|
+
FUNC! contains(arr, value):
|
|
17
|
+
RETURN find(arr, value) != -1
|
|
18
|
+
END!
|
|
19
|
+
|
|
20
|
+
FUNC! reverse_array(arr):
|
|
21
|
+
LET len = LEN(arr)
|
|
22
|
+
LET result = []
|
|
23
|
+
LET i = len - 1
|
|
24
|
+
WHILE? i >= 0:
|
|
25
|
+
result = result + [arr[i]]
|
|
26
|
+
i = i - 1
|
|
27
|
+
END!
|
|
28
|
+
RETURN result
|
|
29
|
+
END!
|
|
30
|
+
|
|
31
|
+
FUNC! sum_array(arr):
|
|
32
|
+
LET total = 0
|
|
33
|
+
LET i = 0
|
|
34
|
+
LET len = LEN(arr)
|
|
35
|
+
WHILE? i < len:
|
|
36
|
+
total = total + arr[i]
|
|
37
|
+
i = i + 1
|
|
38
|
+
END!
|
|
39
|
+
RETURN total
|
|
40
|
+
END!
|
|
41
|
+
|
|
42
|
+
FUNC! max_array(arr):
|
|
43
|
+
IF? LEN(arr) == 0:
|
|
44
|
+
RETURN 0
|
|
45
|
+
END!
|
|
46
|
+
LET m = arr[0]
|
|
47
|
+
LET i = 1
|
|
48
|
+
LET len = LEN(arr)
|
|
49
|
+
WHILE? i < len:
|
|
50
|
+
IF? arr[i] > m:
|
|
51
|
+
m = arr[i]
|
|
52
|
+
END!
|
|
53
|
+
i = i + 1
|
|
54
|
+
END!
|
|
55
|
+
RETURN m
|
|
56
|
+
END!
|
|
57
|
+
|
|
58
|
+
FUNC! min_array(arr):
|
|
59
|
+
IF? LEN(arr) == 0:
|
|
60
|
+
RETURN 0
|
|
61
|
+
END!
|
|
62
|
+
LET m = arr[0]
|
|
63
|
+
LET i = 1
|
|
64
|
+
LET len = LEN(arr)
|
|
65
|
+
WHILE? i < len:
|
|
66
|
+
IF? arr[i] < m:
|
|
67
|
+
m = arr[i]
|
|
68
|
+
END!
|
|
69
|
+
i = i + 1
|
|
70
|
+
END!
|
|
71
|
+
RETURN m
|
|
72
|
+
END!
|
package/std/json.nbs
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Nebulara Standard Library - JSON
|
|
2
|
+
# Simple JSON operations (basic implementation)
|
|
3
|
+
|
|
4
|
+
# JSON is not natively supported yet.
|
|
5
|
+
# These are placeholder functions that demonstrate the API.
|
|
6
|
+
|
|
7
|
+
FUNC! json_stringify(value):
|
|
8
|
+
RETURN TO_STRING(value)
|
|
9
|
+
END!
|
|
10
|
+
|
|
11
|
+
# json_parse is not yet implemented - requires FFI to C JSON parser library
|
|
12
|
+
FUNC! json_parse(str):
|
|
13
|
+
PRINT "JSON.parse: not yet implemented - requires FFI to C JSON parser library"
|
|
14
|
+
RETURN NULL
|
|
15
|
+
END!
|
package/std/kanban.nbs
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Nebulara Standard Library - Kanban
|
|
2
|
+
# Task board data structures and operations
|
|
3
|
+
# Uses arrays for columns and a flat task list
|
|
4
|
+
|
|
5
|
+
# Board state: four column arrays storing task IDs, and a tasks array
|
|
6
|
+
LET _todo = []
|
|
7
|
+
LET _in_progress = []
|
|
8
|
+
LET _review = []
|
|
9
|
+
LET _done = []
|
|
10
|
+
LET _tasks = []
|
|
11
|
+
LET _next_id = 1
|
|
12
|
+
|
|
13
|
+
# Create a new task and add it to the todo column
|
|
14
|
+
FUNC! create_task(title, description, priority):
|
|
15
|
+
LET task = [_next_id, title, description, priority, "todo"]
|
|
16
|
+
_tasks = _tasks + [task]
|
|
17
|
+
_todo = _todo + [_next_id]
|
|
18
|
+
_next_id = _next_id + 1
|
|
19
|
+
RETURN task[0]
|
|
20
|
+
END!
|
|
21
|
+
|
|
22
|
+
# Move a task to a new column
|
|
23
|
+
# status must be: "todo", "in_progress", "review", or "done"
|
|
24
|
+
FUNC! move_task(task_id, new_status):
|
|
25
|
+
LET i = 0
|
|
26
|
+
LET len = LEN(_tasks)
|
|
27
|
+
WHILE? i < len:
|
|
28
|
+
IF? _tasks[i][0] == task_id:
|
|
29
|
+
LET old_status = _tasks[i][4]
|
|
30
|
+
IF? old_status == new_status:
|
|
31
|
+
RETURN TRUE
|
|
32
|
+
END!
|
|
33
|
+
_tasks[i][4] = new_status
|
|
34
|
+
# Remove task_id from old column
|
|
35
|
+
IF? old_status == "todo":
|
|
36
|
+
_todo = _remove_id(_todo, task_id)
|
|
37
|
+
END!
|
|
38
|
+
IF? old_status == "in_progress":
|
|
39
|
+
_in_progress = _remove_id(_in_progress, task_id)
|
|
40
|
+
END!
|
|
41
|
+
IF? old_status == "review":
|
|
42
|
+
_review = _remove_id(_review, task_id)
|
|
43
|
+
END!
|
|
44
|
+
IF? old_status == "done":
|
|
45
|
+
_done = _remove_id(_done, task_id)
|
|
46
|
+
END!
|
|
47
|
+
# Add task_id to new column
|
|
48
|
+
IF? new_status == "todo":
|
|
49
|
+
_todo = _todo + [task_id]
|
|
50
|
+
END!
|
|
51
|
+
IF? new_status == "in_progress":
|
|
52
|
+
_in_progress = _in_progress + [task_id]
|
|
53
|
+
END!
|
|
54
|
+
IF? new_status == "review":
|
|
55
|
+
_review = _review + [task_id]
|
|
56
|
+
END!
|
|
57
|
+
IF? new_status == "done":
|
|
58
|
+
_done = _done + [task_id]
|
|
59
|
+
END!
|
|
60
|
+
RETURN TRUE
|
|
61
|
+
END!
|
|
62
|
+
i = i + 1
|
|
63
|
+
END!
|
|
64
|
+
RETURN FALSE
|
|
65
|
+
END!
|
|
66
|
+
|
|
67
|
+
# Get a task by ID, returns the task array or NULL
|
|
68
|
+
FUNC! get_task(task_id):
|
|
69
|
+
LET i = 0
|
|
70
|
+
LET len = LEN(_tasks)
|
|
71
|
+
WHILE? i < len:
|
|
72
|
+
IF? _tasks[i][0] == task_id:
|
|
73
|
+
RETURN _tasks[i]
|
|
74
|
+
END!
|
|
75
|
+
i = i + 1
|
|
76
|
+
END!
|
|
77
|
+
RETURN NULL
|
|
78
|
+
END!
|
|
79
|
+
|
|
80
|
+
# Print the full board state
|
|
81
|
+
FUNC! print_board():
|
|
82
|
+
PRINT "=== TODO ==="
|
|
83
|
+
_print_column(_todo)
|
|
84
|
+
PRINT "=== IN PROGRESS ==="
|
|
85
|
+
_print_column(_in_progress)
|
|
86
|
+
PRINT "=== REVIEW ==="
|
|
87
|
+
_print_column(_review)
|
|
88
|
+
PRINT "=== DONE ==="
|
|
89
|
+
_print_column(_done)
|
|
90
|
+
END!
|
|
91
|
+
|
|
92
|
+
# Print task summary for a list of task IDs
|
|
93
|
+
FUNC! _print_column(column):
|
|
94
|
+
LET i = 0
|
|
95
|
+
LET len = LEN(column)
|
|
96
|
+
WHILE? i < len:
|
|
97
|
+
LET task = get_task(column[i])
|
|
98
|
+
IF? task != NULL:
|
|
99
|
+
PRINT task[0] + ": " + task[1] + " [" + task[3] + "]"
|
|
100
|
+
END!
|
|
101
|
+
i = i + 1
|
|
102
|
+
END!
|
|
103
|
+
END!
|
|
104
|
+
|
|
105
|
+
# Remove a task ID from an array of IDs, return new array
|
|
106
|
+
FUNC! _remove_id(arr, task_id):
|
|
107
|
+
LET result = []
|
|
108
|
+
LET i = 0
|
|
109
|
+
LET len = LEN(arr)
|
|
110
|
+
WHILE? i < len:
|
|
111
|
+
IF? arr[i] != task_id:
|
|
112
|
+
result = result + [arr[i]]
|
|
113
|
+
END!
|
|
114
|
+
i = i + 1
|
|
115
|
+
END!
|
|
116
|
+
RETURN result
|
|
117
|
+
END!
|
|
118
|
+
|
|
119
|
+
# Count tasks in a column
|
|
120
|
+
FUNC! column_count(column):
|
|
121
|
+
RETURN LEN(column)
|
|
122
|
+
END!
|