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.
Files changed (48) hide show
  1. package/Compiler/nbs-bootstrap.c +2229 -0
  2. package/Compiler/nbs_cli.c +1553 -0
  3. package/Compiler/neb-cli.exe +0 -0
  4. package/Compiler/neb-codegen.c +287 -0
  5. package/Compiler/neb-ffi.c +303 -0
  6. package/Compiler/neb-ir.c +307 -0
  7. package/Compiler/neb-knowledge.c +203 -0
  8. package/Compiler/neb-pipeline.c +787 -0
  9. package/Compiler/neb-semantic.c +261 -0
  10. package/Compiler/nebulara.exe +0 -0
  11. package/README.md +258 -0
  12. package/SPEC.md +267 -0
  13. package/bin/neb.js +36 -0
  14. package/build/neb-cli.exe +0 -0
  15. package/build/neb-codegen.exe +0 -0
  16. package/build/neb-ffi.exe +0 -0
  17. package/build/neb-knowledge.exe +0 -0
  18. package/build/neb-pipeline.exe +0 -0
  19. package/build/nebulara.exe +0 -0
  20. package/dist/index.js +131 -0
  21. package/package.json +39 -0
  22. package/std/collections.nbs +72 -0
  23. package/std/json.nbs +15 -0
  24. package/std/kanban.nbs +122 -0
  25. package/std/math.nbs +52 -0
  26. package/std/net.nbs +22 -0
  27. package/std/primitives.nbs +30 -0
  28. package/std/string.nbs +71 -0
  29. package/std/time.nbs +15 -0
  30. package/test/broken.nbs +2 -0
  31. package/test/hello.nbs +6 -0
  32. package/test/test-arrays.nbs +22 -0
  33. package/test/test-charat.nbs +7 -0
  34. package/test/test-cont-debug.nbs +8 -0
  35. package/test/test-cont-min.nbs +7 -0
  36. package/test/test-cont-parens.nbs +7 -0
  37. package/test/test-cont2.nbs +7 -0
  38. package/test/test-cont3.nbs +7 -0
  39. package/test/test-control.nbs +18 -0
  40. package/test/test-functions.nbs +13 -0
  41. package/test/test-loops.nbs +17 -0
  42. package/test/test-mod-for.nbs +6 -0
  43. package/test/test-mod.nbs +5 -0
  44. package/test/test-new-features.nbs +39 -0
  45. package/test/test-recursion.nbs +23 -0
  46. package/test/test-runtime.nbs +8 -0
  47. package/test/test-strings.nbs +14 -0
  48. package/test/test-trycatch.nbs +11 -0
@@ -0,0 +1,1553 @@
1
+ // Nebulara CLI - Command Line Interface
2
+ // Compiler/nbs_cli.c - The 'nebulara' command
3
+ // Usage: nebulara run <file.nbs> | nebulara build <file.nbs> | nebulara repl
4
+
5
+ #include <stdio.h>
6
+ #include <stdlib.h>
7
+ #include <string.h>
8
+ #include <stdint.h>
9
+ #include <ctype.h>
10
+ #include <time.h>
11
+ #include <math.h>
12
+ #include <inttypes.h>
13
+
14
+ // ============================================================================
15
+ // VM Types (shared with interpreter)
16
+ // ============================================================================
17
+
18
+ #define VAL_NULL 0
19
+ #define VAL_INT 1
20
+ #define VAL_STRING 2
21
+ #define VAL_BOOL 3
22
+ #define VAL_ARRAY 4
23
+ #define VAL_ERROR 5
24
+
25
+ typedef struct Value Value;
26
+ typedef struct { Value* items; int count, cap; } ValueArray;
27
+ struct Value {
28
+ int type;
29
+ union { int64_t i; char* s; int b; ValueArray* a; } as;
30
+ };
31
+
32
+ Value val_int_v(int64_t v) { return (Value){VAL_INT, {.i=v}}; }
33
+ Value val_null_v(void) { return (Value){VAL_NULL, {0}}; }
34
+ Value val_string_v(const char* s) { Value v={VAL_STRING}; v.as.s=strdup(s); return v; }
35
+ Value val_bool_v(int b) { return (Value){VAL_BOOL, {.b=b}}; }
36
+
37
+ const char* val_type_name(Value v) {
38
+ switch(v.type){
39
+ case VAL_NULL: return "null";
40
+ case VAL_INT: return "int";
41
+ case VAL_STRING: return "string";
42
+ case VAL_BOOL: return "bool";
43
+ case VAL_ARRAY: return "array";
44
+ case VAL_ERROR: return "error";
45
+ default: return "unknown";
46
+ }
47
+ }
48
+
49
+ // Deep copy a value (strings are duplicated, arrays are deep-copied)
50
+ Value val_copy(Value v) {
51
+ if (v.type == VAL_STRING) return val_string_v(v.as.s);
52
+ if (v.type == VAL_ARRAY) {
53
+ ValueArray* src = v.as.a;
54
+ ValueArray* dst = calloc(1, sizeof(ValueArray));
55
+ dst->cap = src->count > 0 ? src->count : 8;
56
+ dst->items = calloc(dst->cap, sizeof(Value));
57
+ dst->count = src->count;
58
+ for (int i = 0; i < src->count; i++)
59
+ dst->items[i] = val_copy(src->items[i]);
60
+ Value rv = {VAL_ARRAY}; rv.as.a = dst;
61
+ return rv;
62
+ }
63
+ return v; // int, bool, null are copied by value
64
+ }
65
+
66
+ Value val_to_string(Value v) {
67
+ char buf[128];
68
+ switch(v.type){
69
+ case VAL_NULL: return val_string_v("null");
70
+ case VAL_INT: snprintf(buf,128,"%" PRId64,v.as.i); return val_string_v(buf);
71
+ case VAL_BOOL: return val_string_v(v.as.b?"true":"false");
72
+ case VAL_STRING: return val_string_v(v.as.s);
73
+ case VAL_ARRAY: return val_string_v("[array]");
74
+ case VAL_ERROR: return val_string_v("[error]");
75
+ default: return val_string_v("unknown");
76
+ }
77
+ }
78
+
79
+ int val_truthy(Value v) {
80
+ if (v.type == VAL_NULL) return 0;
81
+ if (v.type == VAL_INT) return v.as.i != 0;
82
+ if (v.type == VAL_BOOL) return v.as.b;
83
+ if (v.type == VAL_STRING) return v.as.s[0] != 0;
84
+ if (v.type == VAL_ARRAY) return v.as.a->count > 0;
85
+ return 0;
86
+ }
87
+
88
+ // Free a value and all its children
89
+ void val_free(Value v) {
90
+ if (v.type == VAL_STRING) { free(v.as.s); return; }
91
+ if (v.type == VAL_ARRAY) {
92
+ ValueArray* a = v.as.a;
93
+ if (a) {
94
+ for (int i = 0; i < a->count; i++) val_free(a->items[i]);
95
+ free(a->items);
96
+ free(a);
97
+ }
98
+ }
99
+ }
100
+
101
+ // ============================================================================
102
+ // OPCODES
103
+ // ============================================================================
104
+
105
+ #define OP_PUSH_INT 0x01
106
+ #define OP_PUSH_STR 0x02
107
+ #define OP_PUSH_BOOL 0x03
108
+ #define OP_POP 0x04
109
+ #define OP_ADD 0x05
110
+ #define OP_SUB 0x06
111
+ #define OP_MUL 0x07
112
+ #define OP_DIV 0x08
113
+ #define OP_MOD 0x09
114
+ #define OP_NEG 0x0A
115
+ #define OP_EQ 0x0B
116
+ #define OP_NEQ 0x0C
117
+ #define OP_LT 0x0D
118
+ #define OP_GT 0x0E
119
+ #define OP_LTE 0x0F
120
+ #define OP_GTE 0x10
121
+ #define OP_AND 0x11
122
+ #define OP_OR 0x12
123
+ #define OP_NOT 0x13
124
+ #define OP_STORE 0x14
125
+ #define OP_LOAD 0x15
126
+ #define OP_PRINT 0x16
127
+ #define OP_JUMP 0x17
128
+ #define OP_JUMP_IFNOT 0x18
129
+ #define OP_HALT 0x19
130
+ #define OP_CALL 0x1A
131
+ #define OP_RET 0x1B
132
+ #define OP_ARRAY_NEW 0x1C
133
+ #define OP_ARRAY_GET 0x1D
134
+ #define OP_ARRAY_LEN 0x1E
135
+ #define OP_TYPEOF 0x1F
136
+ #define OP_TOSTR 0x20
137
+ #define OP_TONUM 0x21
138
+ #define OP_ABS 0x22
139
+ #define OP_STRING_ADD 0x23
140
+ #define OP_MIN 0x24
141
+ #define OP_MAX 0x25
142
+ #define OP_SQRT 0x26
143
+ #define OP_POW 0x27
144
+ #define OP_FLOOR 0x28
145
+ #define OP_CEIL 0x29
146
+ #define OP_ROUND 0x2A
147
+ #define OP_READ_FILE 0x2B
148
+ #define OP_WRITE_FILE 0x2C
149
+ #define OP_ARRAY_PUSH 0x2D
150
+ #define OP_ARRAY_POP 0x2E
151
+ #define OP_SUBSTR 0x2F
152
+ #define OP_CHAR_AT 0x30
153
+ #define OP_TO_UPPER 0x31
154
+ #define OP_TO_LOWER 0x32
155
+ #define OP_WRITE_BYTES 0x47
156
+ #define OP_STR_EQ 0x33
157
+ #define OP_ARRAY_SET 0x34
158
+ #define OP_PUSH_NULL 0x35
159
+ #define OP_DUP 0x36
160
+ #define OP_SWAP 0x37
161
+ #define OP_EXIT 0x38
162
+ #define OP_BREAK 0x39
163
+ #define OP_CONTINUE 0x3A
164
+ #define OP_BITAND 0x3B
165
+ #define OP_BITOR 0x3C
166
+ #define OP_LSHIFT 0x3D
167
+ #define OP_RSHIFT 0x3E
168
+ #define OP_TRY 0x3F
169
+ #define OP_CATCH 0x40
170
+ #define OP_THROW 0x41
171
+ #define OP_FINALLY 0x42
172
+ #define OP_ENDTRY 0x43
173
+ #define OP_CHAR 0x44
174
+ #define OP_ORD 0x45
175
+
176
+ // ============================================================================
177
+ // LEXER
178
+ // ============================================================================
179
+
180
+ typedef enum {
181
+ T_INT, T_STR, T_IDENT, T_PLUS, T_MINUS, T_STAR, T_SLASH, T_MOD,
182
+ T_EQ, T_NEQ, T_LT, T_GT, T_LTE, T_GTE, T_AND, T_OR, T_NOT,
183
+ T_ASSIGN, T_LPAREN, T_RPAREN, T_LBRACKET, T_RBRACKET,
184
+ T_COMMA, T_COLON, T_PRINT, T_IF, T_ELSE, T_ELSEIF, T_THEN,
185
+ T_WHILE, T_FOR, T_TO, T_STEP, T_FUNC, T_END, T_RETURN, T_LET, T_BREAK, T_CONTINUE,
186
+ T_BITAND, T_BITOR, T_LSHIFT, T_RSHIFT,
187
+ T_TRY, T_CATCH, T_THROW, T_FINALLY,
188
+ T_TRUE, T_FALSE, T_NULL,
189
+ T_EOF
190
+ } TT;
191
+
192
+ typedef struct { TT type; char txt[256]; int64_t ival; int line; } Tk;
193
+ typedef struct { const char*s; int p,l,line; } Lx;
194
+
195
+ static Tk tks[8192]; static int tn=0,tp=0;
196
+
197
+ static Tk lx(Lx*l) {
198
+ while(l->p<l->l) {
199
+ char c=l->s[l->p];
200
+ if(c==' '||c=='\t'||c=='\r') { l->p++; continue; }
201
+ if(c=='\n') { l->p++; l->line++; continue; }
202
+ if(c=='#') { while(l->p<l->l&&l->s[l->p]!='\n')l->p++; continue; }
203
+ break;
204
+ }
205
+ Tk t={0};
206
+ t.line=l->line;
207
+ if(l->p>=l->l){t.type=T_EOF;return t;}
208
+ char c=l->s[l->p];
209
+
210
+ if(c>='0'&&c<='9'){
211
+ int64_t v=0;
212
+ while(l->p<l->l&&l->s[l->p]>='0'&&l->s[l->p]<='9')v=v*10+(l->s[l->p++]-'0');
213
+ t.type=T_INT;t.ival=v;return t;
214
+ }
215
+ if(c=='"'){
216
+ l->p++;int i=0;
217
+ while(l->p<l->l&&l->s[l->p]!='"'&&i<254){
218
+ if(l->s[l->p]=='\\'){
219
+ if(l->p+1<l->l){
220
+ l->p++;char e=l->s[l->p++];
221
+ if(e=='n')t.txt[i++]='\n';else if(e=='t')t.txt[i++]='\t';
222
+ else if(e=='\\')t.txt[i++]='\\';else if(e=='"')t.txt[i++]='"';
223
+ else if(e=='0')t.txt[i++]='\0';else t.txt[i++]=e;
224
+ } else { l->p++; }
225
+ } else t.txt[i++]=l->s[l->p++];
226
+ }
227
+ t.txt[i]=0;if(l->p<l->l)l->p++;t.type=T_STR;return t;
228
+ }
229
+ if((c>='a'&&c<='z')||(c>='A'&&c<='Z')||c=='_'){
230
+ int i=0;
231
+ while(l->p<l->l&&i<254&&((l->s[l->p]>='a'&&l->s[l->p]<='z')||(l->s[l->p]>='A'&&l->s[l->p]<='Z')||(l->s[l->p]>='0'&&l->s[l->p]<='9')||l->s[l->p]=='_'||l->s[l->p]=='!'||l->s[l->p]=='?'))t.txt[i++]=l->s[l->p++];
232
+ t.txt[i]=0;
233
+ if(!strcmp(t.txt,"PRINT"))t.type=T_PRINT;
234
+ else if(!strcmp(t.txt,"IF?")||!strcmp(t.txt,"IF"))t.type=T_IF;
235
+ else if(!strcmp(t.txt,"ELSE"))t.type=T_ELSE;
236
+ else if(!strcmp(t.txt,"ELSEIF")||!strcmp(t.txt,"ELSEIF?"))t.type=T_ELSEIF;
237
+ else if(!strcmp(t.txt,"THEN"))t.type=T_THEN;
238
+ else if(!strcmp(t.txt,"WHILE?")||!strcmp(t.txt,"WHILE"))t.type=T_WHILE;
239
+ else if(!strcmp(t.txt,"FOR!"))t.type=T_FOR;
240
+ else if(!strcmp(t.txt,"TO"))t.type=T_TO;
241
+ else if(!strcmp(t.txt,"STEP"))t.type=T_STEP;
242
+ else if(!strcmp(t.txt,"FUNC!"))t.type=T_FUNC;
243
+ else if(!strcmp(t.txt,"END!"))t.type=T_END;
244
+ else if(!strcmp(t.txt,"RETURN"))t.type=T_RETURN;
245
+ else if(!strcmp(t.txt,"LET"))t.type=T_LET;
246
+ else if(!strcmp(t.txt,"AND"))t.type=T_AND;
247
+ else if(!strcmp(t.txt,"OR"))t.type=T_OR;
248
+ else if(!strcmp(t.txt,"NOT"))t.type=T_NOT;
249
+ else if(!strcmp(t.txt,"BREAK"))t.type=T_BREAK;
250
+ else if(!strcmp(t.txt,"CONTINUE"))t.type=T_CONTINUE;
251
+ else if(!strcmp(t.txt,"TRUE")){t.type=T_TRUE;}
252
+ else if(!strcmp(t.txt,"FALSE")){t.type=T_FALSE;}
253
+ else if(!strcmp(t.txt,"NULL")){t.type=T_NULL;}
254
+ else if(!strcmp(t.txt,"TRY!"))t.type=T_TRY;
255
+ else if(!strcmp(t.txt,"CATCH!"))t.type=T_CATCH;
256
+ else if(!strcmp(t.txt,"THROW"))t.type=T_THROW;
257
+ else if(!strcmp(t.txt,"FINALLY!"))t.type=T_FINALLY;
258
+ else t.type=T_IDENT;
259
+ return t;
260
+ }
261
+ l->p++;t.txt[0]=c;t.txt[1]=0;
262
+ switch(c){
263
+ case '+':t.type=T_PLUS;break;case '-':t.type=T_MINUS;break;
264
+ case '*':t.type=T_STAR;break;case '/':t.type=T_SLASH;break;
265
+ case '%':t.type=T_MOD;break;
266
+ case '=':if(l->p<l->l&&l->s[l->p]=='='){l->p++;t.txt[1]='=';t.type=T_EQ;}else t.type=T_ASSIGN;break;
267
+ case '!':if(l->p<l->l&&l->s[l->p]=='='){l->p++;t.txt[1]='=';t.type=T_NEQ;}else t.type=T_NOT;break;
268
+ case '<':if(l->p<l->l&&l->s[l->p]=='='){l->p++;t.txt[1]='=';t.type=T_LTE;}else if(l->p<l->l&&l->s[l->p]=='<'){l->p++;t.txt[1]='<';t.type=T_LSHIFT;}else t.type=T_LT;break;
269
+ case '>':if(l->p<l->l&&l->s[l->p]=='='){l->p++;t.txt[1]='=';t.type=T_GTE;}else if(l->p<l->l&&l->s[l->p]=='>'){l->p++;t.txt[1]='>';t.type=T_RSHIFT;}else t.type=T_GT;break;
270
+ case '&':t.type=T_BITAND;break;
271
+ case '|':t.type=T_BITOR;break;
272
+ case '(':t.type=T_LPAREN;break;case ')':t.type=T_RPAREN;break;
273
+ case '[':t.type=T_LBRACKET;break;case ']':t.type=T_RBRACKET;break;
274
+ case ',':t.type=T_COMMA;break;case ':':t.type=T_COLON;break;
275
+ }
276
+ return t;
277
+ }
278
+
279
+ // ============================================================================
280
+ // BYTECODE COMPILER
281
+ // ============================================================================
282
+
283
+ static uint8_t bytecode[131072];
284
+ static int bclen=0;
285
+ static char strings[65536][256];
286
+ static int strcount=0;
287
+
288
+ // Loop break/continue patch stack
289
+ typedef struct { int break_patches[64]; int break_count; int continue_patches[64]; int continue_count; int continue_ip; } LoopInfo;
290
+ static LoopInfo loop_stack[64];
291
+ static int loop_sp=0;
292
+
293
+ // Try/catch patch stack
294
+ typedef struct { int end_patches[32]; int end_count; } TryInfo;
295
+ static TryInfo try_stack[32];
296
+ static int try_sp=0;
297
+
298
+ static void bc(uint8_t b){
299
+ if(bclen>=131072){fprintf(stderr,"Compiler error: bytecode overflow\n");exit(1);}
300
+ bytecode[bclen++]=b;
301
+ }
302
+ static void bc64(int64_t v){for(int i=0;i<8;i++)bc((v>>(i*8))&0xFF);}
303
+ static void bc32(int32_t v){for(int i=0;i<4;i++)bc((v>>(i*8))&0xFF);}
304
+
305
+ static char varnames[256][64];
306
+ static int varcount=0;
307
+
308
+ static int var_idx(const char* name){
309
+ for(int i=0;i<varcount;i++)if(!strcmp(varnames[i],name))return i;
310
+ if(varcount>=256){fprintf(stderr,"Compiler error: too many variables\n");exit(1);}
311
+ strncpy(varnames[varcount],name,63);varnames[varcount][63]=0;return varcount++;
312
+ }
313
+
314
+ static int str_idx(const char* s){
315
+ for(int i=0;i<strcount;i++)if(!strcmp(strings[i],s))return i;
316
+ if(strcount>=65536){fprintf(stderr,"Compiler error: too many strings\n");exit(1);}
317
+ strncpy(strings[strcount],s,255);strings[strcount][255]=0;return strcount++;
318
+ }
319
+
320
+ // Function table
321
+ typedef struct { char name[64]; int addr; char params[8][64]; int param_count; int entry_varcount; int local_count; } FuncEntry;
322
+ static FuncEntry func_table[256];
323
+ static int func_count=0;
324
+
325
+ static int ft_add(const char* name, int addr) {
326
+ if(func_count>=256){fprintf(stderr,"Compiler error: too many functions\n");exit(1);}
327
+ int idx = func_count++;
328
+ strncpy(func_table[idx].name, name, 63);func_table[idx].name[63]=0;
329
+ func_table[idx].addr = addr;
330
+ func_table[idx].param_count = 0;
331
+ func_table[idx].entry_varcount = 0;
332
+ func_table[idx].local_count = 0;
333
+ return idx;
334
+ }
335
+ static void ft_add_param(int idx, const char* pname) {
336
+ if (idx >= 0 && func_table[idx].param_count < 8) {
337
+ strncpy(func_table[idx].params[func_table[idx].param_count], pname, 63);
338
+ func_table[idx].params[func_table[idx].param_count][63]=0;
339
+ func_table[idx].param_count++;
340
+ }
341
+ }
342
+ static int ft_find(const char* name) {
343
+ for(int i=0;i<func_count;i++) if(!strcmp(func_table[i].name, name)) return i;
344
+ return -1;
345
+ }
346
+
347
+ static void compile_expr(void);
348
+ static void compile_stmt(void);
349
+ static void compile_block(void);
350
+
351
+ static void compile_primary(void) {
352
+ if(tp>=tn)return;
353
+ Tk* t=&tks[tp];
354
+ if(t->type==T_INT){tp++;bc(OP_PUSH_INT);bc64(t->ival);return;}
355
+ if(t->type==T_STR){tp++;int si=str_idx(t->txt);bc(OP_PUSH_STR);bc32(si);return;}
356
+ if(t->type==T_TRUE){tp++;bc(OP_PUSH_BOOL);bc(1);return;}
357
+ if(t->type==T_FALSE){tp++;bc(OP_PUSH_BOOL);bc(0);return;}
358
+ if(t->type==T_NULL){tp++;bc(OP_PUSH_NULL);return;}
359
+ if(t->type==T_IDENT){
360
+ if(tp+1<tn && tks[tp+1].type==T_LPAREN) {
361
+ if(!strcmp(t->txt,"TO_STRING")||!strcmp(t->txt,"TYPEOF")||!strcmp(t->txt,"LEN")||
362
+ !strcmp(t->txt,"TO_NUMBER")||
363
+ !strcmp(t->txt,"ABS")||!strcmp(t->txt,"MIN")||!strcmp(t->txt,"MAX")||
364
+ !strcmp(t->txt,"SQRT")||!strcmp(t->txt,"POW")||!strcmp(t->txt,"FLOOR")||
365
+ !strcmp(t->txt,"CEIL")||!strcmp(t->txt,"ROUND")||!strcmp(t->txt,"READ_FILE")||
366
+ !strcmp(t->txt,"WRITE_FILE")||!strcmp(t->txt,"SUBSTR")||!strcmp(t->txt,"CHAR_AT")||
367
+ !strcmp(t->txt,"TO_UPPER")||!strcmp(t->txt,"TO_LOWER")||
368
+ !strcmp(t->txt,"WRITE_BYTES")||
369
+ !strcmp(t->txt,"CHAR")||!strcmp(t->txt,"ORD")) {
370
+ char fname[64]; strncpy(fname,t->txt,63); fname[63]=0; tp+=2;
371
+ int nargs=0;
372
+ if(tp<tn&&tks[tp].type!=T_RPAREN) {
373
+ compile_expr(); nargs++;
374
+ while(tp<tn&&tks[tp].type==T_COMMA) { tp++; compile_expr(); nargs++; }
375
+ }
376
+ if(tp<tn&&tks[tp].type==T_RPAREN)tp++;
377
+ if(!strcmp(fname,"TO_STRING"))bc(OP_TOSTR);
378
+ else if(!strcmp(fname,"TO_NUMBER"))bc(OP_TONUM);
379
+ else if(!strcmp(fname,"TYPEOF"))bc(OP_TYPEOF);
380
+ else if(!strcmp(fname,"LEN"))bc(OP_ARRAY_LEN);
381
+ else if(!strcmp(fname,"ABS"))bc(OP_ABS);
382
+ else if(!strcmp(fname,"MIN"))bc(OP_MIN);
383
+ else if(!strcmp(fname,"MAX"))bc(OP_MAX);
384
+ else if(!strcmp(fname,"SQRT"))bc(OP_SQRT);
385
+ else if(!strcmp(fname,"POW"))bc(OP_POW);
386
+ else if(!strcmp(fname,"FLOOR"))bc(OP_FLOOR);
387
+ else if(!strcmp(fname,"CEIL"))bc(OP_CEIL);
388
+ else if(!strcmp(fname,"ROUND"))bc(OP_ROUND);
389
+ else if(!strcmp(fname,"READ_FILE"))bc(OP_READ_FILE);
390
+ else if(!strcmp(fname,"WRITE_FILE"))bc(OP_WRITE_FILE);
391
+ else if(!strcmp(fname,"SUBSTR"))bc(OP_SUBSTR);
392
+ else if(!strcmp(fname,"CHAR_AT"))bc(OP_CHAR_AT);
393
+ else if(!strcmp(fname,"TO_UPPER"))bc(OP_TO_UPPER);
394
+ else if(!strcmp(fname,"TO_LOWER"))bc(OP_TO_LOWER);
395
+ else if(!strcmp(fname,"WRITE_BYTES"))bc(OP_WRITE_BYTES);
396
+ else if(!strcmp(fname,"CHAR"))bc(OP_CHAR);
397
+ else if(!strcmp(fname,"ORD"))bc(OP_ORD);
398
+ return;
399
+ }
400
+ // User-defined or unknown function call
401
+ char fname[64]; strncpy(fname, t->txt, 63); fname[63]=0;
402
+ tp+=2; // skip name and (
403
+ // Push args in reverse order
404
+ int arg_count=0;
405
+ while(tp<tn && tks[tp].type!=T_RPAREN) {
406
+ compile_expr();
407
+ arg_count++;
408
+ if(tp<tn && tks[tp].type==T_COMMA) tp++;
409
+ }
410
+ if(tp<tn) tp++; // skip )
411
+ bc(OP_CALL);
412
+ int si=str_idx(fname);
413
+ bc32(si);
414
+ bc32(arg_count);
415
+ return;
416
+ }
417
+ tp++;bc(OP_LOAD);bc32(var_idx(t->txt));
418
+ // Array indexing: arr[i]
419
+ while(tp<tn && tks[tp].type==T_LBRACKET){
420
+ tp++;compile_expr();
421
+ if(tp<tn&&tks[tp].type==T_RBRACKET)tp++;
422
+ bc(OP_ARRAY_GET);
423
+ }
424
+ return;
425
+ }
426
+ if(t->type==T_LPAREN){tp++;compile_expr();if(tp<tn&&tks[tp].type==T_RPAREN)tp++;return;}
427
+ if(t->type==T_MINUS){tp++;compile_primary();bc(OP_NEG);return;}
428
+ if(t->type==T_NOT){tp++;compile_primary();bc(OP_NOT);return;}
429
+ if(t->type==T_LBRACKET){
430
+ tp++;int count=0;
431
+ while(tp<tn&&tks[tp].type!=T_RBRACKET){compile_expr();count++;if(tp<tn&&tks[tp].type==T_COMMA)tp++;}
432
+ if(tp<tn)tp++;
433
+ bc(OP_ARRAY_NEW);bc32(count);return;
434
+ }
435
+ // Fallback: push 0
436
+ tp++;bc(OP_PUSH_INT);bc64(0);
437
+ }
438
+
439
+ // Precedence: 1=multiplicative (* / %), 2=additive (+ - << >> & |), 3=comparison (== != < > <= >=)
440
+ static void compile_mul(void) {
441
+ compile_primary();
442
+ while(tp<tn&&(tks[tp].type==T_STAR||tks[tp].type==T_SLASH||tks[tp].type==T_MOD)){
443
+ TT op=tks[tp].type;tp++;
444
+ compile_primary();
445
+ switch(op){
446
+ case T_STAR:bc(OP_MUL);break;case T_SLASH:bc(OP_DIV);break;
447
+ case T_MOD:bc(OP_MOD);break;default:break;
448
+ }
449
+ }
450
+ }
451
+ static void compile_add(void) {
452
+ compile_mul();
453
+ while(tp<tn&&(tks[tp].type==T_PLUS||tks[tp].type==T_MINUS||
454
+ tks[tp].type==T_BITAND||tks[tp].type==T_BITOR||
455
+ tks[tp].type==T_LSHIFT||tks[tp].type==T_RSHIFT)){
456
+ TT op=tks[tp].type;tp++;
457
+ compile_mul();
458
+ switch(op){
459
+ case T_PLUS:bc(OP_ADD);break;case T_MINUS:bc(OP_SUB);break;
460
+ case T_BITAND:bc(OP_BITAND);break;case T_BITOR:bc(OP_BITOR);break;
461
+ case T_LSHIFT:bc(OP_LSHIFT);break;case T_RSHIFT:bc(OP_RSHIFT);break;
462
+ default:break;
463
+ }
464
+ }
465
+ }
466
+ static void compile_comparison(void) {
467
+ compile_add();
468
+ while(tp<tn&&(tks[tp].type==T_EQ||tks[tp].type==T_NEQ||
469
+ tks[tp].type==T_LT||tks[tp].type==T_GT||
470
+ tks[tp].type==T_LTE||tks[tp].type==T_GTE)){
471
+ TT op=tks[tp].type;tp++;
472
+ compile_add();
473
+ switch(op){
474
+ case T_EQ:bc(OP_EQ);break;case T_NEQ:bc(OP_NEQ);break;
475
+ case T_LT:bc(OP_LT);break;case T_GT:bc(OP_GT);break;
476
+ case T_LTE:bc(OP_LTE);break;case T_GTE:bc(OP_GTE);break;
477
+ default:break;
478
+ }
479
+ }
480
+ }
481
+
482
+ static void compile_expr(void) {
483
+ compile_comparison();
484
+ while(tp<tn&&(tks[tp].type==T_AND||tks[tp].type==T_OR)){
485
+ TT op=tks[tp].type;tp++;
486
+ compile_comparison();
487
+ if(op==T_AND)bc(OP_AND);else bc(OP_OR);
488
+ }
489
+ }
490
+
491
+ static void compile_stmt(void) {
492
+ if(tp>=tn)return;
493
+ Tk* t=&tks[tp];
494
+
495
+ if(t->type==T_BREAK){
496
+ tp++;
497
+ if(loop_sp>0){
498
+ bc(OP_JUMP);int patch=bclen;bc32(0);
499
+ LoopInfo* li=&loop_stack[loop_sp-1];
500
+ if(li->break_count<64) li->break_patches[li->break_count++]=patch;
501
+ }
502
+ return;
503
+ }
504
+ if(t->type==T_CONTINUE){
505
+ tp++;
506
+ if(loop_sp>0){
507
+ LoopInfo* li=&loop_stack[loop_sp-1];
508
+ bc(OP_JUMP);
509
+ if(li->continue_count<64) li->continue_patches[li->continue_count++]=bclen;
510
+ bc32(0); // patched later
511
+ }
512
+ return;
513
+ }
514
+
515
+ // TRY! ... CATCH! err: ... FINALLY! ... END!
516
+ if(t->type==T_TRY){
517
+ tp++;
518
+ // Emit OP_TRY which pushes current IP to try stack and sets catch handler
519
+ bc(OP_TRY);int try_patch=bclen;bc32(0);
520
+ // Compile try body
521
+ compile_block();
522
+ // Jump to end (skip catch/finally)
523
+ bc(OP_JUMP);int end_jump=bclen;bc32(0);
524
+ // Patch try to point to catch handler
525
+ {int32_t o=bclen-try_patch-4;memcpy(bytecode+try_patch,&o,4);}
526
+ // CATCH! block
527
+ if(tp<tn&&tks[tp].type==T_CATCH){
528
+ tp++;
529
+ // Store error in variable if named
530
+ if(tp<tn&&tks[tp].type==T_IDENT){
531
+ int idx=var_idx(tks[tp].txt);tp++;
532
+ bc(OP_STORE);bc32(idx);
533
+ }
534
+ compile_block();
535
+ }
536
+ // FINALLY! block (optional)
537
+ if(tp<tn&&tks[tp].type==T_FINALLY){
538
+ tp++;
539
+ compile_block();
540
+ }
541
+ // Patch end jump
542
+ {int32_t o=bclen-end_jump-4;memcpy(bytecode+end_jump,&o,4);}
543
+ if(tp<tn&&tks[tp].type==T_END)tp++;
544
+ return;
545
+ }
546
+ // THROW expression
547
+ if(t->type==T_THROW){
548
+ tp++;
549
+ compile_expr();
550
+ bc(OP_THROW);
551
+ return;
552
+ }
553
+
554
+ if(t->type==T_PRINT){tp++;compile_expr();bc(OP_PRINT);return;}
555
+
556
+ if(t->type==T_LET){
557
+ tp++;
558
+ if(tp<tn&&tks[tp].type==T_IDENT){
559
+ int idx=var_idx(tks[tp].txt);tp++;
560
+ if(tp<tn&&tks[tp].type==T_ASSIGN)tp++;
561
+ compile_expr();
562
+ bc(OP_STORE);bc32(idx);
563
+ }
564
+ return;
565
+ }
566
+ if(t->type==T_IDENT&&tp+1<tn&&tks[tp+1].type==T_ASSIGN){
567
+ int idx=var_idx(t->txt);tp+=2;
568
+ compile_expr();
569
+ bc(OP_STORE);bc32(idx);
570
+ return;
571
+ }
572
+ // Array indexing assignment: arr[i] = value
573
+ if(t->type==T_IDENT&&tp+2<tn&&tks[tp+1].type==T_LBRACKET){
574
+ int idx=var_idx(t->txt);tp++;
575
+ bc(OP_LOAD);bc32(idx);
576
+ tp++;compile_expr();
577
+ if(tp<tn&&tks[tp].type==T_RBRACKET)tp++;
578
+ if(tp<tn&&tks[tp].type==T_ASSIGN)tp++;
579
+ compile_expr();
580
+ bc(OP_ARRAY_SET);
581
+ bc(OP_STORE);bc32(idx);
582
+ return;
583
+ }
584
+ if(t->type==T_IF){
585
+ tp++;
586
+ compile_expr();
587
+ if(tp<tn&&tks[tp].type==T_THEN)tp++;
588
+ if(tp<tn&&tks[tp].type==T_COLON)tp++;
589
+ bc(OP_JUMP_IFNOT);int p1=bclen;bc32(0);
590
+ compile_block();
591
+ // Track JUMP locations that need patching to END
592
+ int end_patches[64]; int end_patch_count=0;
593
+ // Handle ELSE / ELSEIF chains
594
+ while(tp<tn&&(tks[tp].type==T_ELSE||tks[tp].type==T_ELSEIF)){
595
+ int is_elseif=(tks[tp].type==T_ELSEIF);
596
+ tp++;
597
+ if(is_elseif){
598
+ // ELSEIF? <condition>:
599
+ bc(OP_JUMP);end_patches[end_patch_count++]=bclen;bc32(0);
600
+ {int32_t o=bclen-p1-4;memcpy(bytecode+p1,&o,4);}
601
+ compile_expr();
602
+ if(tp<tn&&tks[tp].type==T_THEN)tp++;
603
+ if(tp<tn&&tks[tp].type==T_COLON)tp++;
604
+ bc(OP_JUMP_IFNOT);p1=bclen;bc32(0);
605
+ }else{
606
+ // Plain ELSE:
607
+ if(tp<tn&&tks[tp].type==T_COLON)tp++;
608
+ bc(OP_JUMP);int p2=bclen;bc32(0);
609
+ {int32_t o=bclen-p1-4;memcpy(bytecode+p1,&o,4);}
610
+ p1=p2; // else block ends at p2
611
+ }
612
+ compile_block();
613
+ }
614
+ // Patch JUMP_IFNOT (fall-through) to END
615
+ {int32_t o=bclen-p1-4;memcpy(bytecode+p1,&o,4);}
616
+ // Patch all ELSEIF skip-to-end JUMPs
617
+ for(int ei=0;ei<end_patch_count;ei++){
618
+ int32_t o=bclen-end_patches[ei]-4;memcpy(bytecode+end_patches[ei],&o,4);
619
+ }
620
+ if(tp<tn&&tks[tp].type==T_END)tp++;
621
+ return;
622
+ }
623
+ if(t->type==T_WHILE){
624
+ tp++;
625
+ int loop=bclen;
626
+ // Push loop info for BREAK/CONTINUE
627
+ loop_stack[loop_sp].break_count=0;
628
+ loop_stack[loop_sp].continue_count=0;
629
+ loop_sp++;
630
+ compile_expr();
631
+ if(tp<tn&&tks[tp].type==T_THEN)tp++;
632
+ if(tp<tn&&tks[tp].type==T_COLON)tp++;
633
+ bc(OP_JUMP_IFNOT);int p1=bclen;bc32(0);
634
+ compile_block();
635
+ bc(OP_JUMP);bc32(loop-bclen-4);
636
+ {int32_t o=bclen-p1-4;memcpy(bytecode+p1,&o,4);}
637
+ // Patch all BREAK jumps to here
638
+ loop_sp--;
639
+ for(int bi=0;bi<loop_stack[loop_sp].break_count;bi++){
640
+ int patch=loop_stack[loop_sp].break_patches[bi];
641
+ int32_t o=bclen-patch-4;memcpy(bytecode+patch,&o,4);
642
+ }
643
+ // Patch all CONTINUE jumps to loop start
644
+ for(int ci=0;ci<loop_stack[loop_sp].continue_count;ci++){
645
+ int patch=loop_stack[loop_sp].continue_patches[ci];
646
+ int32_t o=loop-patch-4;memcpy(bytecode+patch,&o,4);
647
+ }
648
+ if(tp<tn&&tks[tp].type==T_END)tp++;
649
+ return;
650
+ }
651
+ if(t->type==T_FOR){
652
+ tp++;
653
+ if(tp<tn&&tks[tp].type==T_IDENT){
654
+ int idx=var_idx(tks[tp].txt);tp++;
655
+ if(tp<tn&&tks[tp].type==T_ASSIGN)tp++;
656
+ compile_expr(); // start
657
+ bc(OP_STORE);bc32(idx);
658
+ if(tp<tn&&tks[tp].type==T_TO)tp++;
659
+ compile_expr(); // end
660
+ int end_idx=var_idx("__for_end");
661
+ bc(OP_STORE);bc32(end_idx);
662
+ // Optional STEP
663
+ int step_idx=-1;
664
+ if(tp<tn&&tks[tp].type==T_STEP){
665
+ tp++;
666
+ compile_expr(); // step value
667
+ step_idx=var_idx("__for_step");
668
+ bc(OP_STORE);bc32(step_idx);
669
+ }
670
+
671
+ int loop=bclen;
672
+ loop_stack[loop_sp].break_count=0;
673
+ loop_stack[loop_sp].continue_count=0;
674
+ loop_sp++;
675
+ bc(OP_LOAD);bc32(idx);
676
+ bc(OP_LOAD);bc32(end_idx);
677
+ bc(OP_LTE); // current <= end
678
+ bc(OP_JUMP_IFNOT);int p1=bclen;bc32(0);
679
+ // body
680
+ if(tp<tn&&tks[tp].type==T_COLON)tp++;
681
+ compile_block();
682
+ // Record increment position for CONTINUE patching
683
+ int increment_pos=bclen;
684
+ // increment
685
+ bc(OP_LOAD);bc32(idx);
686
+ if(step_idx>=0){
687
+ bc(OP_LOAD);bc32(step_idx);
688
+ }else{
689
+ bc(OP_PUSH_INT);bc64(1);
690
+ }
691
+ bc(OP_ADD);
692
+ bc(OP_STORE);bc32(idx);
693
+ bc(OP_JUMP);bc32(loop-bclen-4);
694
+ {int32_t o=bclen-p1-4;memcpy(bytecode+p1,&o,4);}
695
+ // Patch all BREAK jumps
696
+ loop_sp--;
697
+ for(int bi=0;bi<loop_stack[loop_sp].break_count;bi++){
698
+ int patch=loop_stack[loop_sp].break_patches[bi];
699
+ int32_t o=bclen-patch-4;memcpy(bytecode+patch,&o,4);
700
+ }
701
+ // Patch all CONTINUE jumps to increment step
702
+ for(int ci=0;ci<loop_stack[loop_sp].continue_count;ci++){
703
+ int patch=loop_stack[loop_sp].continue_patches[ci];
704
+ int32_t o=increment_pos-patch-4;memcpy(bytecode+patch,&o,4);
705
+ }
706
+ }
707
+ if(tp<tn&&tks[tp].type==T_END)tp++;
708
+ return;
709
+ }
710
+ if(t->type==T_FUNC){
711
+ tp++;
712
+ // Parse: FUNC! name param1 param2 ... : body END!
713
+ if(tp<tn && tks[tp].type==T_IDENT) {
714
+ char fname[64]; strncpy(fname, tks[tp].txt, 63); fname[63]=0;
715
+ int fi = ft_add(fname, bclen);
716
+ func_table[fi].entry_varcount = varcount;
717
+ tp++;
718
+ // Parse parameters
719
+ while(tp<tn && tks[tp].type!=T_COLON && tks[tp].type!=T_END && tks[tp].type!=T_EOF) {
720
+ if(tks[tp].type==T_IDENT) {
721
+ ft_add_param(fi, tks[tp].txt);
722
+ }
723
+ tp++;
724
+ }
725
+ if(tp<tn && tks[tp].type==T_COLON) tp++;
726
+ // Emit JUMP over body
727
+ bc(OP_JUMP); int skip_patch=bclen; bc32(0);
728
+ // Record correct function address (after the JUMP)
729
+ func_table[fi].addr = bclen;
730
+ // Compile body
731
+ compile_block();
732
+ // Record local variable count for this function
733
+ func_table[fi].local_count = varcount - func_table[fi].entry_varcount;
734
+ // Implicit return 0
735
+ bc(OP_PUSH_INT); bc64(0); bc(OP_RET);
736
+ // Patch JUMP to skip over body
737
+ {int32_t o=bclen-skip_patch-4; memcpy(bytecode+skip_patch, &o, 4);}
738
+ if(tp<tn && tks[tp].type==T_END) tp++;
739
+ }
740
+ return;
741
+ }
742
+ if(t->type==T_RETURN){
743
+ tp++;
744
+ if(tp<tn&&tks[tp].type!=T_END&&tks[tp].type!=T_EOF)compile_expr();
745
+ else bc(OP_PUSH_INT),bc64(0);
746
+ bc(OP_RET);return;
747
+ }
748
+ // Expression statement
749
+ compile_expr();
750
+ }
751
+
752
+ static void compile_block(void) {
753
+ while(tp<tn&&tks[tp].type!=T_END&&tks[tp].type!=T_ELSE&&tks[tp].type!=T_ELSEIF&&tks[tp].type!=T_CATCH&&tks[tp].type!=T_FINALLY&&tks[tp].type!=T_EOF)compile_stmt();
754
+ }
755
+
756
+ // ============================================================================
757
+ // VM EXECUTION
758
+ // ============================================================================
759
+
760
+ #define VM_STACK_SIZE 4096
761
+ #define VM_VAR_SIZE 4096
762
+ #define VM_CALL_STACK_SIZE 256
763
+ #define VM_MAX_INSTRUCTIONS 2000000000LL
764
+
765
+ static Value vm_stack[VM_STACK_SIZE];
766
+ static int vm_sp=0;
767
+ static Value vm_vars[VM_VAR_SIZE];
768
+ static int vm_var_sp=0;
769
+ static int vm_var_base=0;
770
+ static int vm_running=1;
771
+ static int g_argc=0;
772
+ static char** g_argv=NULL;
773
+
774
+ // Error state
775
+ static char vm_error_msg[256]= {0};
776
+ static int vm_has_error=0;
777
+
778
+ // VM exception handler stack
779
+ typedef struct { int handler_ip; int saved_sp; int saved_call_sp; } VMTryFrame;
780
+ static VMTryFrame vm_try_stack[32];
781
+ static int vm_try_sp=0;
782
+
783
+ typedef struct { int ret_ip; int var_base; int var_sp; int saved_var_idx[256]; Value saved_vars[256]; int saved_count; } VMCallFrame;
784
+ static VMCallFrame vm_call_stack[VM_CALL_STACK_SIZE];
785
+ static int vm_call_sp=0;
786
+
787
+ // VM error handling
788
+ static int vm_handler_ip = -1; // Set by OP_TRY, checked by errors
789
+ static void vm_set_error(const char* msg) {
790
+ snprintf(vm_error_msg, 256, "%s", msg);
791
+ // Check if we have a try handler
792
+ if(vm_try_sp > 0) {
793
+ vm_try_sp--;
794
+ vm_sp = vm_try_stack[vm_try_sp].saved_sp;
795
+ vm_call_sp = vm_try_stack[vm_try_sp].saved_call_sp;
796
+ // Push error message on stack
797
+ vm_stack[vm_sp++] = val_string_v(msg);
798
+ // Signal to vm_exec to jump
799
+ vm_handler_ip = vm_try_stack[vm_try_sp].handler_ip;
800
+ vm_has_error = 0; // Clear error so VM continues
801
+ } else {
802
+ vm_has_error = 1;
803
+ }
804
+ }
805
+
806
+ static void vm_push(Value v) {
807
+ if(vm_sp >= VM_STACK_SIZE) {
808
+ vm_set_error("Stack overflow");
809
+ return;
810
+ }
811
+ vm_stack[vm_sp++] = v;
812
+ }
813
+
814
+ static Value vm_pop(void) {
815
+ if(vm_sp <= 0) {
816
+ vm_set_error("Stack underflow");
817
+ return val_null_v();
818
+ }
819
+ return vm_stack[--vm_sp];
820
+ }
821
+
822
+ static void vm_exec(uint8_t* code, int len, char strtable[][256], int strcount) {
823
+ int ip=0;
824
+ long long ins_count=0;
825
+ vm_has_error = 0;
826
+ vm_error_msg[0] = 0;
827
+ vm_handler_ip = -1;
828
+
829
+ while(ip<len && !vm_has_error){
830
+ // Check if we need to jump to exception handler
831
+ if(vm_handler_ip >= 0) {
832
+ ip = vm_handler_ip;
833
+ vm_handler_ip = -1;
834
+ continue;
835
+ }
836
+ uint8_t op=code[ip];
837
+ ins_count++;
838
+ if(ins_count>VM_MAX_INSTRUCTIONS) {
839
+ fprintf(stderr, "Runtime error: instruction limit exceeded (%lld instructions)\n", VM_MAX_INSTRUCTIONS);
840
+ return;
841
+ }
842
+ ip++;
843
+ switch(op){
844
+ case OP_PUSH_INT:{int64_t v;memcpy(&v,code+ip,8);ip+=8;vm_push(val_int_v(v));}break;
845
+ case OP_PUSH_STR:{int32_t si;memcpy(&si,code+ip,4);ip+=4;
846
+ if(si>=0 && si<strcount) vm_push(val_string_v(strtable[si]));
847
+ else { vm_set_error("Invalid string index"); return; }
848
+ }break;
849
+ case OP_PUSH_BOOL:{uint8_t b=code[ip++];vm_push(val_bool_v(b));}break;
850
+ case OP_PUSH_NULL:{vm_push(val_null_v());}break;
851
+ case OP_ADD:{Value b=vm_pop(),a=vm_pop();
852
+ if(a.type==VAL_ARRAY&&b.type==VAL_ARRAY){
853
+ ValueArray*aa=a.as.a,*ba=b.as.a;
854
+ int nc=aa->count+ba->count;
855
+ ValueArray*result=calloc(1,sizeof(ValueArray));
856
+ result->cap=nc>0?nc:8;result->items=calloc(result->cap,sizeof(Value));result->count=0;
857
+ for(int i=0;i<aa->count;i++)result->items[result->count++]=val_copy(aa->items[i]);
858
+ for(int i=0;i<ba->count;i++)result->items[result->count++]=val_copy(ba->items[i]);
859
+ Value vr={VAL_ARRAY};vr.as.a=result;vm_push(vr);val_free(a);val_free(b);
860
+ } else if(a.type==VAL_ARRAY){
861
+ ValueArray*aa=a.as.a;
862
+ int nc=aa->count+1;
863
+ ValueArray*result=calloc(1,sizeof(ValueArray));
864
+ result->cap=nc;result->items=calloc(result->cap,sizeof(Value));result->count=0;
865
+ for(int i=0;i<aa->count;i++)result->items[result->count++]=val_copy(aa->items[i]);
866
+ result->items[result->count++]=val_copy(b);
867
+ Value vr={VAL_ARRAY};vr.as.a=result;vm_push(vr);val_free(a);val_free(b);
868
+ } else if(b.type==VAL_ARRAY){
869
+ ValueArray*ba=b.as.a;
870
+ int nc=1+ba->count;
871
+ ValueArray*result=calloc(1,sizeof(ValueArray));
872
+ result->cap=nc;result->items=calloc(result->cap,sizeof(Value));result->count=0;
873
+ result->items[result->count++]=val_copy(a);
874
+ for(int i=0;i<ba->count;i++)result->items[result->count++]=val_copy(ba->items[i]);
875
+ Value vr={VAL_ARRAY};vr.as.a=result;vm_push(vr);val_free(a);val_free(b);
876
+ } else if(a.type==VAL_INT&&b.type==VAL_INT)vm_push(val_int_v(a.as.i+b.as.i));
877
+ else{Value sa=val_to_string(a),sb=val_to_string(b);
878
+ int len2=(int)strlen(sa.as.s)+(int)strlen(sb.as.s)+1;
879
+ char*buf=malloc(len2);strcpy(buf,sa.as.s);strcat(buf,sb.as.s);
880
+ val_free(sa);val_free(sb);val_free(a);val_free(b);
881
+ vm_push(val_string_v(buf));free(buf);}
882
+ }break;
883
+ case OP_SUB:{Value b=vm_pop(),a=vm_pop();
884
+ if(a.type==VAL_INT&&b.type==VAL_INT) vm_push(val_int_v(a.as.i-b.as.i));
885
+ else vm_push(val_int_v(0));
886
+ val_free(a);val_free(b);}break;
887
+ case OP_MUL:{Value b=vm_pop(),a=vm_pop();
888
+ if(a.type==VAL_INT&&b.type==VAL_INT) vm_push(val_int_v(a.as.i*b.as.i));
889
+ else vm_push(val_int_v(0));
890
+ val_free(a);val_free(b);}break;
891
+ case OP_DIV:{Value b=vm_pop(),a=vm_pop();
892
+ if(a.type!=VAL_INT||b.type!=VAL_INT){vm_set_error("Division requires integers");val_free(a);val_free(b);}
893
+ else if(b.as.i==0){vm_set_error("Division by zero");val_free(a);val_free(b);}
894
+ else{vm_push(val_int_v(a.as.i/b.as.i));val_free(a);val_free(b);}
895
+ }break;
896
+ case OP_MOD:{Value b=vm_pop(),a=vm_pop();
897
+ if(a.type!=VAL_INT||b.type!=VAL_INT){vm_set_error("Modulo requires integers");val_free(a);val_free(b);}
898
+ else if(b.as.i==0){vm_set_error("Modulo by zero");val_free(a);val_free(b);}
899
+ else{vm_push(val_int_v(a.as.i%b.as.i));val_free(a);val_free(b);}
900
+ }break;
901
+ case OP_NEG:{Value a=vm_pop();vm_push(val_int_v(-a.as.i));val_free(a);}break;
902
+ case OP_EQ:{Value b=vm_pop(),a=vm_pop();
903
+ int eq=(a.type==b.type)?(
904
+ a.type==VAL_NULL?1:a.type==VAL_INT?a.as.i==b.as.i:
905
+ a.type==VAL_BOOL?a.as.b==b.as.b:a.type==VAL_STRING?strcmp(a.as.s,b.as.s)==0:0):0;
906
+ vm_push(val_bool_v(eq));val_free(a);val_free(b);
907
+ }break;
908
+ case OP_NEQ:{Value b=vm_pop(),a=vm_pop();
909
+ int eq=(a.type==b.type)?(
910
+ a.type==VAL_NULL?1:a.type==VAL_INT?a.as.i==b.as.i:
911
+ a.type==VAL_BOOL?a.as.b==b.as.b:a.type==VAL_STRING?strcmp(a.as.s,b.as.s)==0:0):0;
912
+ vm_push(val_bool_v(!eq));val_free(a);val_free(b);
913
+ }break;
914
+ case OP_LT:{Value b=vm_pop(),a=vm_pop();
915
+ if(a.type==VAL_INT&&b.type==VAL_INT) vm_push(val_bool_v(a.as.i<b.as.i));
916
+ else if(a.type==VAL_STRING&&b.type==VAL_STRING) vm_push(val_bool_v(strcmp(a.as.s,b.as.s)<0));
917
+ else vm_push(val_bool_v(0));
918
+ val_free(a);val_free(b);}break;
919
+ case OP_GT:{Value b=vm_pop(),a=vm_pop();
920
+ if(a.type==VAL_INT&&b.type==VAL_INT) vm_push(val_bool_v(a.as.i>b.as.i));
921
+ else if(a.type==VAL_STRING&&b.type==VAL_STRING) vm_push(val_bool_v(strcmp(a.as.s,b.as.s)>0));
922
+ else vm_push(val_bool_v(0));
923
+ val_free(a);val_free(b);}break;
924
+ case OP_LTE:{Value b=vm_pop(),a=vm_pop();
925
+ if(a.type==VAL_INT&&b.type==VAL_INT) vm_push(val_bool_v(a.as.i<=b.as.i));
926
+ else vm_push(val_bool_v(0));
927
+ val_free(a);val_free(b);}break;
928
+ case OP_GTE:{Value b=vm_pop(),a=vm_pop();
929
+ if(a.type==VAL_INT&&b.type==VAL_INT) vm_push(val_bool_v(a.as.i>=b.as.i));
930
+ else vm_push(val_bool_v(0));
931
+ val_free(a);val_free(b);}break;
932
+ case OP_AND:{Value b=vm_pop(),a=vm_pop();vm_push(val_bool_v(val_truthy(a)&&val_truthy(b)));val_free(a);val_free(b);}break;
933
+ case OP_OR:{Value b=vm_pop(),a=vm_pop();vm_push(val_bool_v(val_truthy(a)||val_truthy(b)));val_free(a);val_free(b);}break;
934
+ case OP_NOT:{Value a=vm_pop();vm_push(val_bool_v(!val_truthy(a)));val_free(a);}break;
935
+ case OP_BITAND:{Value b=vm_pop(),a=vm_pop();vm_push(val_int_v(a.as.i&b.as.i));val_free(a);val_free(b);}break;
936
+ case OP_BITOR:{Value b=vm_pop(),a=vm_pop();vm_push(val_int_v(a.as.i|b.as.i));val_free(a);val_free(b);}break;
937
+ case OP_LSHIFT:{Value b=vm_pop(),a=vm_pop();vm_push(val_int_v(a.as.i<<(int)b.as.i));val_free(a);val_free(b);}break;
938
+ case OP_RSHIFT:{Value b=vm_pop(),a=vm_pop();vm_push(val_int_v(a.as.i>>(int)b.as.i));val_free(a);val_free(b);}break;
939
+ case OP_STORE:{int32_t idx;memcpy(&idx,code+ip,4);ip+=4;
940
+ int vi=vm_var_base+idx;
941
+ if(vi<0||vi>=VM_VAR_SIZE){vm_set_error("Variable index out of bounds");break;}
942
+ val_free(vm_vars[vi]);vm_vars[vi]=vm_pop();
943
+ }break;
944
+ case OP_LOAD:{int32_t idx;memcpy(&idx,code+ip,4);ip+=4;
945
+ int vi=vm_var_base+idx;
946
+ if(vi<0||vi>=VM_VAR_SIZE){vm_set_error("Variable index out of bounds");break;}
947
+ Value v=vm_vars[vi];
948
+ if(v.type==VAL_STRING)vm_push(val_string_v(v.as.s));
949
+ else if(v.type==VAL_ARRAY){
950
+ ValueArray* src=v.as.a;
951
+ ValueArray* dst=calloc(1,sizeof(ValueArray));
952
+ dst->cap=src->count>0?src->count:8;
953
+ dst->items=calloc(dst->cap,sizeof(Value));
954
+ dst->count=src->count;
955
+ for(int i=0;i<src->count;i++)dst->items[i]=val_copy(src->items[i]);
956
+ Value rv={VAL_ARRAY};rv.as.a=dst;vm_push(rv);
957
+ } else vm_push(v);
958
+ }break;
959
+ case OP_PRINT:{Value v=vm_pop();Value s=val_to_string(v);
960
+ printf("%s\n",s.as.s);
961
+ val_free(s);val_free(v);
962
+ }break;
963
+ case OP_JUMP:{int32_t off;memcpy(&off,code+ip,4);ip+=4;ip+=off;}break;
964
+ case OP_JUMP_IFNOT:{int32_t off;memcpy(&off,code+ip,4);ip+=4;Value v=vm_pop();
965
+ if(!val_truthy(v))ip+=off;
966
+ val_free(v);}break;
967
+ case OP_ARRAY_NEW:{int32_t count;memcpy(&count,code+ip,4);ip+=4;
968
+ Value arr={VAL_ARRAY};arr.as.a=calloc(1,sizeof(ValueArray));
969
+ arr.as.a->cap=count>0?count:8;arr.as.a->items=calloc(arr.as.a->cap,sizeof(Value));arr.as.a->count=0;
970
+ for(int i=0;i<count;i++)arr.as.a->items[arr.as.a->count++]=vm_pop();
971
+ // Reverse
972
+ for(int i=0;i<arr.as.a->count/2;i++){Value tmp=arr.as.a->items[i];arr.as.a->items[i]=arr.as.a->items[arr.as.a->count-1-i];arr.as.a->items[arr.as.a->count-1-i]=tmp;}
973
+ vm_push(arr);
974
+ }break;
975
+ case OP_ARRAY_GET:{Value idx=vm_pop(),arr=vm_pop();
976
+ if(arr.type==VAL_ARRAY && idx.type==VAL_INT){
977
+ int i=(int)idx.as.i;
978
+ if(i>=0 && i<arr.as.a->count){
979
+ Value v=arr.as.a->items[i];
980
+ if(v.type==VAL_STRING) vm_push(val_string_v(v.as.s));
981
+ else vm_push(v);
982
+ } else { vm_push(val_null_v()); }
983
+ } else { vm_push(val_null_v()); }
984
+ val_free(arr);val_free(idx);
985
+ }break;
986
+ case OP_TOSTR:{Value v=vm_pop();Value s=val_to_string(v);val_free(v);vm_push(s);}break;
987
+ case OP_TONUM:{Value v=vm_pop();
988
+ if(v.type==VAL_STRING){int64_t n=atoll(v.as.s);val_free(v);vm_push(val_int_v(n));}
989
+ else if(v.type==VAL_INT){vm_push(v);}
990
+ else{val_free(v);vm_push(val_int_v(0));}
991
+ }break;
992
+ case OP_TYPEOF:{Value v=vm_pop();const char*tn2=val_type_name(v);vm_push(val_string_v(tn2));val_free(v);}break;
993
+ case OP_ARRAY_LEN:{Value v=vm_pop();
994
+ if(v.type==VAL_ARRAY){int c=v.as.a->count;vm_push(val_int_v(c));val_free(v);}
995
+ else if(v.type==VAL_STRING){int c=(int)strlen(v.as.s);vm_push(val_int_v(c));val_free(v);}
996
+ else{val_free(v);vm_push(val_int_v(0));}
997
+ }break;
998
+ case OP_ABS:{Value v=vm_pop();if(v.type==VAL_INT&&v.as.i<0)v.as.i=-v.as.i;vm_push(v);}break;
999
+ case OP_MIN:{Value b=vm_pop(),a=vm_pop();
1000
+ int64_t va=a.type==VAL_INT?a.as.i:0, vb=b.type==VAL_INT?b.as.i:0;
1001
+ vm_push(val_int_v(va<vb?va:vb));val_free(a);val_free(b);}break;
1002
+ case OP_MAX:{Value b=vm_pop(),a=vm_pop();
1003
+ int64_t va=a.type==VAL_INT?a.as.i:0, vb=b.type==VAL_INT?b.as.i:0;
1004
+ vm_push(val_int_v(va>vb?va:vb));val_free(a);val_free(b);}break;
1005
+ case OP_SQRT:{Value v=vm_pop();
1006
+ double d=v.type==VAL_INT?(double)v.as.i:0;
1007
+ vm_push(val_int_v((int64_t)sqrt(d)));val_free(v);}break;
1008
+ case OP_POW:{Value b=vm_pop(),a=vm_pop();
1009
+ double base=a.type==VAL_INT?(double)a.as.i:0;
1010
+ double exp=b.type==VAL_INT?(double)b.as.i:0;
1011
+ vm_push(val_int_v((int64_t)pow(base,exp)));val_free(a);val_free(b);}break;
1012
+ case OP_FLOOR:{Value v=vm_pop();
1013
+ if(v.type==VAL_INT)vm_push(v);
1014
+ else{val_free(v);vm_push(val_int_v(0));}}break;
1015
+ case OP_CEIL:{Value v=vm_pop();
1016
+ if(v.type==VAL_INT)vm_push(v);
1017
+ else{val_free(v);vm_push(val_int_v(0));}}break;
1018
+ case OP_ROUND:{Value v=vm_pop();
1019
+ if(v.type==VAL_INT)vm_push(v);
1020
+ else{val_free(v);vm_push(val_int_v(0));}}break;
1021
+ case OP_READ_FILE:{Value v=vm_pop();
1022
+ if(v.type==VAL_STRING){
1023
+ FILE*f=fopen(v.as.s,"rb");
1024
+ if(f){fseek(f,0,SEEK_END);long fsize=ftell(f);
1025
+ if(fsize<0){fclose(f);vm_push(val_string_v(""));}
1026
+ else{fseek(f,0,SEEK_SET);
1027
+ char*buf=malloc(fsize+1);size_t read=fread(buf,1,fsize,f);buf[read]=0;fclose(f);
1028
+ vm_push(val_string_v(buf));free(buf);}}
1029
+ else{vm_set_error("Cannot open file");vm_push(val_string_v(""));}
1030
+ }else{val_free(v);vm_set_error("READ_FILE requires string argument");vm_push(val_string_v(""));}}break;
1031
+ case OP_WRITE_FILE:{Value v2=vm_pop(),v1=vm_pop();
1032
+ if(v1.type==VAL_STRING&&v2.type==VAL_STRING){
1033
+ FILE*f=fopen(v1.as.s,"wb");
1034
+ if(f){fwrite(v2.as.s,1,strlen(v2.as.s),f);fclose(f);}
1035
+ else{vm_set_error("Cannot write file");}
1036
+ }
1037
+ val_free(v1);val_free(v2);vm_push(val_int_v(0));}break;
1038
+ case OP_WRITE_BYTES:{Value arr=vm_pop(),fn=vm_pop();
1039
+ if(fn.type==VAL_STRING&&arr.type==VAL_ARRAY){
1040
+ FILE*f=fopen(fn.as.s,"wb");
1041
+ if(f){
1042
+ for(int i=0;i<arr.as.a->count;i++){
1043
+ uint8_t b=(uint8_t)(arr.as.a->items[i].as.i&0xFF);
1044
+ fwrite(&b,1,1,f);
1045
+ }
1046
+ fclose(f);
1047
+ } else { vm_set_error("Cannot write file"); }
1048
+ }
1049
+ val_free(fn);val_free(arr);vm_push(val_int_v(0));}break;
1050
+ case OP_ARRAY_PUSH:{Value val=vm_pop(),arr=vm_pop();
1051
+ if(arr.type==VAL_ARRAY){
1052
+ if(arr.as.a->count>=arr.as.a->cap){
1053
+ int newcap=arr.as.a->cap*2;
1054
+ Value* newitems=realloc(arr.as.a->items,newcap*sizeof(Value));
1055
+ if(!newitems){vm_set_error("Out of memory");val_free(val);val_free(arr);break;}
1056
+ arr.as.a->items=newitems;
1057
+ arr.as.a->cap=newcap;
1058
+ }
1059
+ arr.as.a->items[arr.as.a->count++]=val;
1060
+ } else val_free(val);
1061
+ vm_push(arr);
1062
+ }break;
1063
+ case OP_ARRAY_POP:{Value arr=vm_pop();
1064
+ if(arr.type==VAL_ARRAY && arr.as.a->count>0){
1065
+ Value v=arr.as.a->items[--arr.as.a->count];
1066
+ if(v.type==VAL_STRING)vm_push(val_string_v(v.as.s));
1067
+ else if(v.type==VAL_ARRAY) vm_push(val_copy(v));
1068
+ else vm_push(v);
1069
+ } else vm_push(val_null_v());
1070
+ val_free(arr);
1071
+ }break;
1072
+ case OP_ARRAY_SET:{Value val=vm_pop(),idx=vm_pop(),arr=vm_pop();
1073
+ if(arr.type==VAL_ARRAY && idx.type==VAL_INT){
1074
+ int i=(int)idx.as.i;
1075
+ if(i>=0 && i<arr.as.a->count){val_free(arr.as.a->items[i]);arr.as.a->items[i]=val;}
1076
+ else val_free(val);
1077
+ } else val_free(val);
1078
+ vm_push(arr);
1079
+ }break;
1080
+ case OP_SUBSTR:{Value len=vm_pop(),start=vm_pop(),str=vm_pop();
1081
+ if(str.type==VAL_STRING && start.type==VAL_INT && len.type==VAL_INT){
1082
+ int s=(int)start.as.i, l=(int)len.as.i, slen=(int)strlen(str.as.s);
1083
+ if(s<0)s=0; if(s>slen)s=slen; if(s+l>slen)l=slen-s;
1084
+ if(l<0)l=0;
1085
+ char*buf=malloc(l+1);memcpy(buf,str.as.s+s,l);buf[l]=0;
1086
+ vm_push(val_string_v(buf));free(buf);
1087
+ } else { vm_push(val_string_v("")); }
1088
+ val_free(str);val_free(start);val_free(len);
1089
+ }break;
1090
+ case OP_CHAR_AT:{Value idx=vm_pop(),str=vm_pop();
1091
+ if(str.type==VAL_STRING && idx.type==VAL_INT){
1092
+ int i=(int)idx.as.i; int slen=(int)strlen(str.as.s);
1093
+ if(i>=0 && i<slen){vm_push(val_int_v((int)(unsigned char)str.as.s[i]));}
1094
+ else vm_push(val_int_v(0));
1095
+ } else vm_push(val_int_v(0));
1096
+ val_free(str);val_free(idx);
1097
+ }break;
1098
+ case OP_TO_UPPER:{Value v=vm_pop();
1099
+ if(v.type==VAL_STRING){char*buf=strdup(v.as.s);for(char*p=buf;*p;p++)*p=(char)toupper((unsigned char)*p);vm_push(val_string_v(buf));free(buf);}
1100
+ else vm_push(v);
1101
+ }break;
1102
+ case OP_TO_LOWER:{Value v=vm_pop();
1103
+ if(v.type==VAL_STRING){char*buf=strdup(v.as.s);for(char*p=buf;*p;p++)*p=(char)tolower((unsigned char)*p);vm_push(val_string_v(buf));free(buf);}
1104
+ else vm_push(v);
1105
+ }break;
1106
+ case OP_STR_EQ:{Value b=vm_pop(),a=vm_pop();
1107
+ int eq=0;
1108
+ if(a.type==VAL_STRING && b.type==VAL_STRING) eq=(strcmp(a.as.s,b.as.s)==0);
1109
+ vm_push(val_bool_v(eq));val_free(a);val_free(b);
1110
+ }break;
1111
+ case OP_DUP:{Value v=vm_stack[vm_sp-1];
1112
+ if(v.type==VAL_STRING) vm_push(val_string_v(v.as.s));
1113
+ else if(v.type==VAL_ARRAY) vm_push(val_copy(v));
1114
+ else vm_push(v);
1115
+ }break;
1116
+ case OP_SWAP:{Value b=vm_pop(),a=vm_pop();vm_push(b);vm_push(a);}break;
1117
+ case OP_EXIT:{int code2=0;if(vm_sp>0){Value v=vm_pop();if(v.type==VAL_INT)code2=(int)v.as.i;val_free(v);}exit(code2);}break;
1118
+ case OP_CHAR:{Value v=vm_pop();
1119
+ if(v.type==VAL_INT){char buf[2]={(char)v.as.i,0};vm_push(val_string_v(buf));}
1120
+ else{val_free(v);vm_push(val_string_v(""));}
1121
+ }break;
1122
+ case OP_ORD:{Value v=vm_pop();
1123
+ if(v.type==VAL_STRING && strlen(v.as.s)>0){vm_push(val_int_v((int)(unsigned char)v.as.s[0]));val_free(v);}
1124
+ else{val_free(v);vm_push(val_int_v(0));}
1125
+ }break;
1126
+ case OP_THROW:{Value v=vm_pop();
1127
+ if(vm_try_sp > 0) {
1128
+ // Set error and let vm_set_error handle the jump
1129
+ vm_set_error(v.type==VAL_STRING ? v.as.s : "Exception thrown");
1130
+ val_free(v);
1131
+ } else {
1132
+ fprintf(stderr, "Uncaught exception: ");
1133
+ if(v.type==VAL_STRING) fprintf(stderr, "%s\n", v.as.s);
1134
+ else { Value s=val_to_string(v); fprintf(stderr, "%s\n", s.as.s); val_free(s); }
1135
+ val_free(v);
1136
+ vm_has_error = 1;
1137
+ }
1138
+ }break;
1139
+ case OP_TRY:{int32_t handler_off;memcpy(&handler_off,code+ip,4);ip+=4;
1140
+ // Push handler onto try stack
1141
+ if(vm_try_sp < 32) {
1142
+ vm_try_stack[vm_try_sp].handler_ip = ip + handler_off;
1143
+ vm_try_stack[vm_try_sp].saved_sp = vm_sp;
1144
+ vm_try_stack[vm_try_sp].saved_call_sp = vm_call_sp;
1145
+ vm_try_sp++;
1146
+ }
1147
+ }break;
1148
+ case OP_CATCH:{/* handled by compiler with JUMP patching */}break;
1149
+ case OP_FINALLY:{/* handled by compiler with JUMP patching */}break;
1150
+ case OP_ENDTRY:{if(vm_try_sp>0)vm_try_sp--;}break;
1151
+ case OP_CALL:{int32_t name_idx;memcpy(&name_idx,code+ip,4);ip+=4;
1152
+ int32_t arity;memcpy(&arity,code+ip,4);ip+=4;
1153
+ if(name_idx<0||name_idx>=strcount){vm_set_error("Invalid function name index");break;}
1154
+ const char* name=strings[name_idx];
1155
+ // Built-in functions
1156
+ if(!strcmp(name,"LEN")){Value v=vm_pop();
1157
+ if(v.type==VAL_STRING){vm_push(val_int_v((int64_t)strlen(v.as.s)));val_free(v);}
1158
+ else if(v.type==VAL_ARRAY){vm_push(val_int_v(v.as.a->count));val_free(v);}
1159
+ else{val_free(v);vm_push(val_int_v(0));}
1160
+ } else if(!strcmp(name,"TYPEOF")){Value v=vm_pop();vm_push(val_string_v(val_type_name(v)));val_free(v);}
1161
+ else if(!strcmp(name,"TO_STRING")){Value v=vm_pop();vm_push(val_to_string(v));val_free(v);}
1162
+ else if(!strcmp(name,"TO_NUMBER")){Value v=vm_pop();
1163
+ if(v.type==VAL_STRING){int64_t n=atoll(v.as.s);val_free(v);vm_push(val_int_v(n));}
1164
+ else if(v.type==VAL_INT){vm_push(v);}
1165
+ else{val_free(v);vm_push(val_int_v(0));}
1166
+ } else if(!strcmp(name,"RANDOM")){for(int i=0;i<arity;i++)val_free(vm_pop());vm_push(val_int_v(rand()%100));}
1167
+ else if(!strcmp(name,"TIME")){for(int i=0;i<arity;i++)val_free(vm_pop());vm_push(val_int_v((int64_t)time(NULL)));}
1168
+ else if(!strcmp(name,"ABS")){Value v=vm_pop();if(v.type==VAL_INT&&v.as.i<0)v.as.i=-v.as.i;vm_push(v);}
1169
+ else if(!strcmp(name,"ARGUMENT_COUNT")){for(int i=0;i<arity;i++)val_free(vm_pop());vm_push(val_int_v(g_argc));}
1170
+ else if(!strcmp(name,"ARGUMENT")){Value v=vm_pop();
1171
+ if(v.type==VAL_INT && v.as.i>=0 && v.as.i<g_argc){
1172
+ vm_push(val_string_v(g_argv[v.as.i]));
1173
+ } else { val_free(v); vm_push(val_string_v("")); }
1174
+ } else if(!strcmp(name,"CHAR")){Value v=vm_pop();
1175
+ if(v.type==VAL_INT){char buf[2]={(char)v.as.i,0};vm_push(val_string_v(buf));}
1176
+ else{val_free(v);vm_push(val_string_v(""));}
1177
+ } else if(!strcmp(name,"ORD")){Value v=vm_pop();
1178
+ if(v.type==VAL_STRING && strlen(v.as.s)>0){vm_push(val_int_v((int)(unsigned char)v.as.s[0]));val_free(v);}
1179
+ else{val_free(v);vm_push(val_int_v(0));}
1180
+ } else if(!strcmp(name,"READ_FILE")){Value v=vm_pop();
1181
+ if(v.type==VAL_STRING){
1182
+ FILE*f=fopen(v.as.s,"rb");
1183
+ if(f){fseek(f,0,SEEK_END);long fsize=ftell(f);
1184
+ if(fsize<0){fclose(f);vm_push(val_string_v(""));}
1185
+ else{fseek(f,0,SEEK_SET);
1186
+ char*buf=malloc(fsize+1);size_t r=fread(buf,1,fsize,f);buf[r]=0;fclose(f);
1187
+ vm_push(val_string_v(buf));free(buf);}}
1188
+ else{vm_set_error("Cannot open file");vm_push(val_string_v(""));}
1189
+ }else{val_free(v);vm_set_error("READ_FILE requires string");vm_push(val_string_v(""));}
1190
+ } else if(!strcmp(name,"WRITE_FILE")){Value v2=vm_pop(),v1=vm_pop();
1191
+ if(v1.type==VAL_STRING&&v2.type==VAL_STRING){
1192
+ FILE*f=fopen(v1.as.s,"wb");
1193
+ if(f){fwrite(v2.as.s,1,strlen(v2.as.s),f);fclose(f);}
1194
+ else{vm_set_error("Cannot write file");}
1195
+ }
1196
+ val_free(v1);val_free(v2);vm_push(val_int_v(0));
1197
+ } else if(!strcmp(name,"WRITE_BYTES")){Value arr=vm_pop(),fn=vm_pop();
1198
+ if(fn.type==VAL_STRING&&arr.type==VAL_ARRAY){
1199
+ FILE*f=fopen(fn.as.s,"wb");
1200
+ if(f){
1201
+ for(int i=0;i<arr.as.a->count;i++){
1202
+ uint8_t b=(uint8_t)(arr.as.a->items[i].as.i&0xFF);
1203
+ fwrite(&b,1,1,f);
1204
+ }
1205
+ fclose(f);
1206
+ } else { vm_set_error("Cannot write file"); }
1207
+ }
1208
+ val_free(fn);val_free(arr);vm_push(val_int_v(0));
1209
+ } else {
1210
+ // User-defined function
1211
+ int fi=ft_find(name);
1212
+ if(fi<0){
1213
+ char errmsg[256];snprintf(errmsg,256,"Undefined function '%s'",name);
1214
+ vm_set_error(errmsg);break;
1215
+ }
1216
+ if(vm_call_sp>=VM_CALL_STACK_SIZE){vm_set_error("Call stack overflow");break;}
1217
+ // Save return address + old var_base
1218
+ vm_call_stack[vm_call_sp].ret_ip=ip;
1219
+ vm_call_stack[vm_call_sp].var_base=vm_var_base;
1220
+ vm_call_stack[vm_call_sp].var_sp=vm_var_sp;
1221
+ vm_call_stack[vm_call_sp].saved_count=0;
1222
+ // Save param slots and local variable slots
1223
+ int sc=0;
1224
+ // Mark which indices have been saved (to avoid duplicates)
1225
+ int saved_flag[256]={0};
1226
+ // 1) Save param slots (will be overwritten by args)
1227
+ int pcount=func_table[fi].param_count<arity?func_table[fi].param_count:arity;
1228
+ for(int i=0;i<pcount;i++){
1229
+ const char* pname=func_table[fi].params[i];
1230
+ int gidx=var_idx(pname);
1231
+ if(gidx>=0 && gidx<256 && !saved_flag[gidx] && sc<256){
1232
+ vm_call_stack[vm_call_sp].saved_var_idx[sc]=gidx;
1233
+ vm_call_stack[vm_call_sp].saved_vars[sc]=vm_vars[gidx];
1234
+ vm_call_stack[vm_call_sp].saved_count=++sc;
1235
+ saved_flag[gidx]=1;
1236
+ }
1237
+ }
1238
+ // 2) Save local variables (new names created inside function body)
1239
+ int ev=func_table[fi].entry_varcount;
1240
+ int lc=func_table[fi].local_count;
1241
+ for(int i=ev;i<ev+lc && i<256;i++){
1242
+ if(!saved_flag[i] && sc<256){
1243
+ vm_call_stack[vm_call_sp].saved_var_idx[sc]=i;
1244
+ vm_call_stack[vm_call_sp].saved_vars[sc]=vm_vars[i];
1245
+ vm_call_stack[vm_call_sp].saved_count=++sc;
1246
+ saved_flag[i]=1;
1247
+ }
1248
+ }
1249
+ // Assign params in REVERSE order so params[0] gets leftmost arg
1250
+ for(int i=pcount-1;i>=0;i--){
1251
+ const char* pname=func_table[fi].params[i];
1252
+ int gidx=var_idx(pname);
1253
+ if(gidx>=0 && gidx<VM_VAR_SIZE){
1254
+ vm_vars[gidx]=vm_pop();
1255
+ }
1256
+ }
1257
+ vm_call_sp++;
1258
+ // Discard remaining args
1259
+ for(int i=arity;i>func_table[fi].param_count;i--)val_free(vm_pop());
1260
+ // Jump to function
1261
+ ip=func_table[fi].addr;
1262
+ }
1263
+ }break;
1264
+ case OP_RET:{Value v=vm_pop();
1265
+ if(vm_call_sp>0){vm_call_sp--;
1266
+ // Restore saved global variable slots
1267
+ for(int i=0;i<vm_call_stack[vm_call_sp].saved_count;i++){
1268
+ int gidx=vm_call_stack[vm_call_sp].saved_var_idx[i];
1269
+ if(gidx>=0 && gidx<VM_VAR_SIZE){
1270
+ val_free(vm_vars[gidx]);
1271
+ vm_vars[gidx]=vm_call_stack[vm_call_sp].saved_vars[i];
1272
+ }
1273
+ }
1274
+ ip=vm_call_stack[vm_call_sp].ret_ip;
1275
+ vm_var_base=vm_call_stack[vm_call_sp].var_base;
1276
+ vm_var_sp=vm_call_stack[vm_call_sp].var_sp;}
1277
+ else{vm_push(v);return;}
1278
+ vm_push(v);
1279
+ }break;
1280
+ case OP_HALT:return;
1281
+ default:
1282
+ fprintf(stderr, "Runtime error: unknown opcode 0x%02X at ip=%d\n", op, ip-1);
1283
+ return;
1284
+ }
1285
+ }
1286
+ if(vm_has_error) {
1287
+ fprintf(stderr, "Runtime error: %s\n", vm_error_msg);
1288
+ }
1289
+ }
1290
+
1291
+ // ============================================================================
1292
+ // CLI
1293
+ // ============================================================================
1294
+
1295
+ static void print_version(void) {
1296
+ fprintf(stderr, "Nebulara v2.0 - AI-Native Programming Language\n");
1297
+ fprintf(stderr, "Usage:\n");
1298
+ fprintf(stderr, " nebulara run <file.nbs> Execute a .nbs file\n");
1299
+ fprintf(stderr, " nebulara build <file.nbs> Compile to bytecode\n");
1300
+ fprintf(stderr, " nebulara repl Interactive REPL\n");
1301
+ fprintf(stderr, " nebulara version Show version\n");
1302
+ fprintf(stderr, " nebulara help Show this help\n");
1303
+ fprintf(stderr, " nebulara highlight <file> Syntax highlight\n");
1304
+ }
1305
+
1306
+ static void cleanup_vm(void) {
1307
+ for (int i = 0; i < VM_VAR_SIZE; i++) val_free(vm_vars[i]);
1308
+ for (int i = 0; i < vm_sp; i++) val_free(vm_stack[i]);
1309
+ memset(vm_vars, 0, sizeof(vm_vars));
1310
+ memset(vm_stack, 0, sizeof(vm_stack));
1311
+ }
1312
+
1313
+ static int run_file(const char* path) {
1314
+ FILE* f = fopen(path, "rb");
1315
+ if (!f) { fprintf(stderr, "Error: cannot open '%s'\n", path); return 1; }
1316
+ fseek(f, 0, SEEK_END);
1317
+ long len = ftell(f);
1318
+ if(len<0){fclose(f);fprintf(stderr,"Error: cannot determine file size\n");return 1;}
1319
+ fseek(f, 0, SEEK_SET);
1320
+ char* src = (char*)malloc(len + 1);
1321
+ if(!src){fclose(f);fprintf(stderr,"Error: out of memory\n");return 1;}
1322
+ size_t read=fread(src, 1, len, f);
1323
+ src[read] = 0;
1324
+ fclose(f);
1325
+
1326
+ // Reset compiler state
1327
+ func_count = 0;
1328
+
1329
+ // Lex
1330
+ Lx lx_state = {src, 0, (int)read, 1};
1331
+ tn = 0; tp = 0;
1332
+ do { tks[tn++] = lx(&lx_state); } while (tks[tn-1].type != T_EOF && tn < 8192);
1333
+
1334
+ // Compile
1335
+ bclen = 0;
1336
+ varcount = 0;
1337
+ strcount = 0;
1338
+ while (tp < tn && tks[tp].type != T_EOF) compile_stmt();
1339
+ bc(OP_HALT);
1340
+ fprintf(stderr, "Compiled %d bytes, %d variables, %d strings, %d functions\n", bclen, varcount, strcount, func_count);
1341
+
1342
+ // Reset VM state
1343
+ cleanup_vm();
1344
+ vm_sp = 0;
1345
+ vm_var_sp = 0;
1346
+ vm_var_base = 0;
1347
+ vm_call_sp = 0;
1348
+ vm_running = 1;
1349
+ for (int i = 0; i < strcount; i++) vm_vars[i].type = VAL_NULL;
1350
+
1351
+ // Execute
1352
+ vm_exec(bytecode, bclen, strings, strcount);
1353
+
1354
+ // Cleanup
1355
+ cleanup_vm();
1356
+ free(src);
1357
+ return vm_has_error ? 1 : 0;
1358
+ }
1359
+
1360
+ static int build_file(const char* path) {
1361
+ FILE* f = fopen(path, "rb");
1362
+ if (!f) { fprintf(stderr, "Error: cannot open '%s'\n", path); return 1; }
1363
+ fseek(f, 0, SEEK_END);
1364
+ long len = ftell(f);
1365
+ if(len<0){fclose(f);fprintf(stderr,"Error: cannot determine file size\n");return 1;}
1366
+ fseek(f, 0, SEEK_SET);
1367
+ char* src = (char*)malloc(len + 1);
1368
+ if(!src){fclose(f);fprintf(stderr,"Error: out of memory\n");return 1;}
1369
+ size_t read=fread(src, 1, len, f);
1370
+ src[read] = 0;
1371
+ fclose(f);
1372
+
1373
+ // Reset compiler state
1374
+ func_count = 0;
1375
+
1376
+ // Lex
1377
+ Lx lx_state = {src, 0, (int)read, 1};
1378
+ tn = 0; tp = 0;
1379
+ do { tks[tn++] = lx(&lx_state); } while (tks[tn-1].type != T_EOF && tn < 8192);
1380
+
1381
+ // Compile
1382
+ bclen = 0;
1383
+ varcount = 0;
1384
+ strcount = 0;
1385
+ while (tp < tn && tks[tp].type != T_EOF) compile_stmt();
1386
+ bc(OP_HALT);
1387
+
1388
+ // Write bytecode
1389
+ char outpath[512];
1390
+ snprintf(outpath, sizeof(outpath), "%s.nbsc", path);
1391
+ FILE* out = fopen(outpath, "wb");
1392
+ if (!out) { fprintf(stderr, "Error: cannot write '%s'\n", outpath); free(src); return 1; }
1393
+ // Write header: magic, version, counts
1394
+ fwrite("NBS1", 1, 4, out);
1395
+ uint32_t ver=2;fwrite(&ver,4,1,out);
1396
+ uint32_t bc32=(uint32_t)bclen;fwrite(&bc32,4,1,out);
1397
+ uint32_t sc32=(uint32_t)strcount;fwrite(&sc32,4,1,out);
1398
+ uint32_t fc32=(uint32_t)func_count;fwrite(&fc32,4,1,out);
1399
+ // Write string table
1400
+ for(int i=0;i<strcount;i++){
1401
+ uint32_t slen=(uint32_t)strlen(strings[i]);
1402
+ fwrite(&slen,4,1,out);
1403
+ fwrite(strings[i],1,slen,out);
1404
+ }
1405
+ // Write function table
1406
+ for(int i=0;i<func_count;i++){
1407
+ uint32_t nlen=(uint32_t)strlen(func_table[i].name);
1408
+ fwrite(&nlen,4,1,out);
1409
+ fwrite(func_table[i].name,1,nlen,out);
1410
+ fwrite(&func_table[i].addr,4,1,out);
1411
+ fwrite(&func_table[i].param_count,4,1,out);
1412
+ for(int j=0;j<func_table[i].param_count;j++){
1413
+ uint32_t plen=(uint32_t)strlen(func_table[i].params[j]);
1414
+ fwrite(&plen,4,1,out);
1415
+ fwrite(func_table[i].params[j],1,plen,out);
1416
+ }
1417
+ }
1418
+ // Write bytecode
1419
+ fwrite(bytecode, 1, bclen, out);
1420
+ fclose(out);
1421
+ printf("Compiled %s -> %s (%d bytes, %d functions)\n", path, outpath, bclen, func_count);
1422
+ free(src);
1423
+ return 0;
1424
+ }
1425
+
1426
+ // Syntax highlighting (simple ANSI terminal output)
1427
+ static int highlight_file(const char* path) {
1428
+ FILE* f = fopen(path, "rb");
1429
+ if (!f) { fprintf(stderr, "Error: cannot open '%s'\n", path); return 1; }
1430
+ fseek(f, 0, SEEK_END);
1431
+ long len = ftell(f);
1432
+ if(len<0){fclose(f);return 1;}
1433
+ fseek(f, 0, SEEK_SET);
1434
+ char* src = (char*)malloc(len + 1);
1435
+ if(!src){fclose(f);return 1;}
1436
+ size_t read=fread(src, 1, len, f);
1437
+ src[read] = 0;
1438
+ fclose(f);
1439
+
1440
+ Lx lx_state = {src, 0, (int)read, 1};
1441
+ int token_count = 0;
1442
+ Tk tokens[8192];
1443
+ do { tokens[token_count++] = lx(&lx_state); } while (tokens[token_count-1].type != T_EOF && token_count < 8192);
1444
+
1445
+ for(int i=0; i<token_count; i++){
1446
+ Tk* t = &tokens[i];
1447
+ switch(t->type){
1448
+ case T_INT: printf("\033[33m%lld\033[0m", t->ival); break;
1449
+ case T_STR: printf("\033[32m\"%s\"\033[0m", t->txt); break;
1450
+ case T_PRINT: case T_IF: case T_ELSE: case T_ELSEIF: case T_THEN:
1451
+ case T_WHILE: case T_FOR: case T_TO: case T_FUNC: case T_END:
1452
+ case T_RETURN: case T_LET: case T_BREAK: case T_CONTINUE:
1453
+ case T_AND: case T_OR: case T_NOT:
1454
+ case T_TRY: case T_CATCH: case T_THROW: case T_FINALLY:
1455
+ printf("\033[36m%s\033[0m", t->txt); break;
1456
+ case T_IDENT: printf("\033[37m%s\033[0m", t->txt); break;
1457
+ case T_PLUS: case T_MINUS: case T_STAR: case T_SLASH: case T_MOD:
1458
+ case T_EQ: case T_NEQ: case T_LT: case T_GT: case T_LTE: case T_GTE:
1459
+ case T_ASSIGN: case T_BITAND: case T_BITOR: case T_LSHIFT: case T_RSHIFT:
1460
+ printf("\033[35m%s\033[0m", t->txt); break;
1461
+ case T_LPAREN: case T_RPAREN: case T_LBRACKET: case T_RBRACKET:
1462
+ printf("\033[33m%s\033[0m", t->txt); break;
1463
+ case T_COMMA: case T_COLON:
1464
+ printf("\033[37m%s\033[0m", t->txt); break;
1465
+ case T_EOF: break;
1466
+ default: printf("%s", t->txt); break;
1467
+ }
1468
+ // Add space after tokens (except at line end)
1469
+ if(i < token_count-1 && tokens[i].type != T_EOF){
1470
+ if(tokens[i].line != tokens[i+1].line) printf("\n");
1471
+ else if(tokens[i+1].type != T_COMMA && tokens[i+1].type != T_COLON &&
1472
+ tokens[i].type != T_COMMA && tokens[i].type != T_COLON &&
1473
+ tokens[i].type != T_LPAREN && tokens[i+1].type != T_RPAREN &&
1474
+ tokens[i].type != T_LBRACKET && tokens[i+1].type != T_RBRACKET)
1475
+ printf(" ");
1476
+ }
1477
+ }
1478
+ printf("\n");
1479
+ free(src);
1480
+ return 0;
1481
+ }
1482
+
1483
+ static void repl(void) {
1484
+ printf("Nebulara v2.0 > Type 'exit' to quit\n");
1485
+ char line[1024];
1486
+ // Initialize VM state for REPL
1487
+ memset(vm_vars, 0, sizeof(vm_vars));
1488
+ func_count = 0;
1489
+ while (1) {
1490
+ printf(">> ");
1491
+ fflush(stdout);
1492
+ if (!fgets(line, sizeof(line), stdin)) break;
1493
+ // Remove newline
1494
+ int len = (int)strlen(line);
1495
+ while (len > 0 && (line[len-1]=='\n'||line[len-1]=='\r')) line[--len]=0;
1496
+ if (len == 0) continue;
1497
+ if (strcmp(line, "exit") == 0 || strcmp(line, "quit") == 0) break;
1498
+
1499
+ // Lex + compile + run inline
1500
+ Lx lx_state = {line, 0, len, 1};
1501
+ tn = 0; tp = 0;
1502
+ do { tks[tn++] = lx(&lx_state); } while (tks[tn-1].type != T_EOF && tn < 8192);
1503
+
1504
+ bclen = 0;
1505
+ int saved_varcount = varcount;
1506
+ int saved_strcount = strcount;
1507
+ while (tp < tn && tks[tp].type != T_EOF) compile_stmt();
1508
+ bc(OP_HALT);
1509
+
1510
+ // Reset VM stack (but keep variables for REPL persistence)
1511
+ for (int i = 0; i < vm_sp; i++) val_free(vm_stack[i]);
1512
+ vm_sp = 0;
1513
+ vm_call_sp = 0;
1514
+ vm_running = 1;
1515
+ vm_has_error = 0;
1516
+
1517
+ vm_exec(bytecode, bclen, strings, strcount);
1518
+
1519
+ if(vm_has_error) fprintf(stderr, "Error: %s\n", vm_error_msg);
1520
+ }
1521
+ cleanup_vm();
1522
+ }
1523
+
1524
+ int main(int argc, char** argv) {
1525
+ if (argc < 2) { print_version(); return 0; }
1526
+
1527
+ // Store global args for ARGUMENT_COUNT/ARGUMENT builtins
1528
+ g_argc = argc;
1529
+ g_argv = argv;
1530
+
1531
+ if (strcmp(argv[1], "run") == 0) {
1532
+ if (argc < 3) { fprintf(stderr, "Usage: nebulara run <file.nbs>\n"); return 1; }
1533
+ return run_file(argv[2]);
1534
+ } else if (strcmp(argv[1], "build") == 0) {
1535
+ if (argc < 3) { fprintf(stderr, "Usage: nebulara build <file.nbs>\n"); return 1; }
1536
+ return build_file(argv[2]);
1537
+ } else if (strcmp(argv[1], "highlight") == 0) {
1538
+ if (argc < 3) { fprintf(stderr, "Usage: nebulara highlight <file.nbs>\n"); return 1; }
1539
+ return highlight_file(argv[2]);
1540
+ } else if (strcmp(argv[1], "repl") == 0) {
1541
+ repl();
1542
+ return 0;
1543
+ } else if (strcmp(argv[1], "version") == 0) {
1544
+ fprintf(stderr, "Nebulara v2.0\n");
1545
+ return 0;
1546
+ } else if (strcmp(argv[1], "help") == 0) {
1547
+ print_version();
1548
+ return 0;
1549
+ } else {
1550
+ // If it's a file, just run it
1551
+ return run_file(argv[1]);
1552
+ }
1553
+ }