Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
7639 views
1
#include "jsi.h"
2
#include "jsparse.h"
3
#include "jscompile.h"
4
#include "jsvalue.h"
5
6
#include "utf.h"
7
8
#include <assert.h>
9
10
static const char *astname[] = {
11
#include "astnames.h"
12
};
13
14
static const char *opname[] = {
15
#include "opnames.h"
16
};
17
18
const char *jsP_aststring(enum js_AstType type)
19
{
20
if (type < nelem(astname))
21
return astname[type];
22
return "<unknown>";
23
}
24
25
const char *jsC_opcodestring(enum js_OpCode opcode)
26
{
27
if (opcode < nelem(opname))
28
return opname[opcode];
29
return "<unknown>";
30
}
31
32
static int prec(enum js_AstType type)
33
{
34
switch (type) {
35
case EXP_IDENTIFIER:
36
case EXP_NUMBER:
37
case EXP_STRING:
38
case EXP_REGEXP:
39
case EXP_UNDEF:
40
case EXP_NULL:
41
case EXP_TRUE:
42
case EXP_FALSE:
43
case EXP_THIS:
44
case EXP_ARRAY:
45
case EXP_OBJECT:
46
return 170;
47
48
case EXP_FUN:
49
case EXP_INDEX:
50
case EXP_MEMBER:
51
case EXP_CALL:
52
case EXP_NEW:
53
return 160;
54
55
case EXP_POSTINC:
56
case EXP_POSTDEC:
57
return 150;
58
59
case EXP_DELETE:
60
case EXP_VOID:
61
case EXP_TYPEOF:
62
case EXP_PREINC:
63
case EXP_PREDEC:
64
case EXP_POS:
65
case EXP_NEG:
66
case EXP_BITNOT:
67
case EXP_LOGNOT:
68
return 140;
69
70
case EXP_MOD:
71
case EXP_DIV:
72
case EXP_MUL:
73
return 130;
74
75
case EXP_SUB:
76
case EXP_ADD:
77
return 120;
78
79
case EXP_USHR:
80
case EXP_SHR:
81
case EXP_SHL:
82
return 110;
83
84
case EXP_IN:
85
case EXP_INSTANCEOF:
86
case EXP_GE:
87
case EXP_LE:
88
case EXP_GT:
89
case EXP_LT:
90
return 100;
91
92
case EXP_STRICTNE:
93
case EXP_STRICTEQ:
94
case EXP_NE:
95
case EXP_EQ:
96
return 90;
97
98
case EXP_BITAND: return 80;
99
case EXP_BITXOR: return 70;
100
case EXP_BITOR: return 60;
101
case EXP_LOGAND: return 50;
102
case EXP_LOGOR: return 40;
103
104
case EXP_COND:
105
return 30;
106
107
case EXP_ASS:
108
case EXP_ASS_MUL:
109
case EXP_ASS_DIV:
110
case EXP_ASS_MOD:
111
case EXP_ASS_ADD:
112
case EXP_ASS_SUB:
113
case EXP_ASS_SHL:
114
case EXP_ASS_SHR:
115
case EXP_ASS_USHR:
116
case EXP_ASS_BITAND:
117
case EXP_ASS_BITXOR:
118
case EXP_ASS_BITOR:
119
return 20;
120
121
#define COMMA 15
122
123
case EXP_COMMA:
124
return 10;
125
126
default:
127
return 0;
128
}
129
}
130
131
static void pc(int c)
132
{
133
putchar(c);
134
}
135
136
static void ps(const char *s)
137
{
138
fputs(s, stdout);
139
}
140
141
static void in(int d)
142
{
143
while (d-- > 0)
144
putchar('\t');
145
}
146
147
static void nl(void)
148
{
149
putchar('\n');
150
}
151
152
/* Pretty-printed Javascript syntax */
153
154
static void pstmlist(int d, js_Ast *list);
155
static void pexpi(int d, int i, js_Ast *exp);
156
static void pstm(int d, js_Ast *stm);
157
static void slist(int d, js_Ast *list);
158
static void sblock(int d, js_Ast *list);
159
160
static void pargs(int d, js_Ast *list)
161
{
162
while (list) {
163
assert(list->type == AST_LIST);
164
pexpi(d, COMMA, list->a);
165
list = list->b;
166
if (list)
167
ps(", ");
168
}
169
}
170
171
static void parray(int d, js_Ast *list)
172
{
173
ps("[");
174
while (list) {
175
assert(list->type == AST_LIST);
176
pexpi(d, COMMA, list->a);
177
list = list->b;
178
if (list)
179
ps(", ");
180
}
181
ps("]");
182
}
183
184
static void pobject(int d, js_Ast *list)
185
{
186
ps("{");
187
while (list) {
188
js_Ast *kv = list->a;
189
assert(list->type == AST_LIST);
190
switch (kv->type) {
191
case EXP_PROP_VAL:
192
pexpi(d, COMMA, kv->a);
193
ps(": ");
194
pexpi(d, COMMA, kv->b);
195
break;
196
case EXP_PROP_GET:
197
ps("get ");
198
pexpi(d, COMMA, kv->a);
199
ps("() {\n");
200
pstmlist(d, kv->c);
201
in(d); ps("}");
202
break;
203
case EXP_PROP_SET:
204
ps("set ");
205
pexpi(d, COMMA, kv->a);
206
ps("(");
207
pargs(d, kv->b);
208
ps(") {\n");
209
pstmlist(d, kv->c);
210
in(d); ps("}");
211
break;
212
}
213
list = list->b;
214
if (list)
215
ps(", ");
216
}
217
ps("}");
218
}
219
220
static void pstr(const char *s)
221
{
222
static const char *HEX = "0123456789ABCDEF";
223
Rune c;
224
pc('"');
225
while (*s) {
226
s += chartorune(&c, s);
227
switch (c) {
228
case '"': ps("\\\""); break;
229
case '\\': ps("\\\\"); break;
230
case '\b': ps("\\b"); break;
231
case '\f': ps("\\f"); break;
232
case '\n': ps("\\n"); break;
233
case '\r': ps("\\r"); break;
234
case '\t': ps("\\t"); break;
235
default:
236
if (c < ' ' || c > 127) {
237
ps("\\u");
238
pc(HEX[(c>>12)&15]);
239
pc(HEX[(c>>8)&15]);
240
pc(HEX[(c>>4)&15]);
241
pc(HEX[c&15]);
242
} else {
243
pc(c); break;
244
}
245
}
246
}
247
pc('"');
248
}
249
250
static void pregexp(const char *prog, int flags)
251
{
252
pc('/');
253
ps(prog);
254
pc('/');
255
if (flags & JS_REGEXP_G) pc('g');
256
if (flags & JS_REGEXP_I) pc('i');
257
if (flags & JS_REGEXP_M) pc('m');
258
}
259
260
static void pbin(int d, int p, js_Ast *exp, const char *op)
261
{
262
pexpi(d, p, exp->a);
263
ps(op);
264
pexpi(d, p, exp->b);
265
}
266
267
static void puna(int d, int p, js_Ast *exp, const char *pre, const char *suf)
268
{
269
ps(pre);
270
pexpi(d, p, exp->a);
271
ps(suf);
272
}
273
274
static void pexpi(int d, int p, js_Ast *exp)
275
{
276
int tp = prec(exp->type);
277
int paren = 0;
278
if (tp < p) {
279
pc('(');
280
paren = 1;
281
}
282
p = tp;
283
284
switch (exp->type) {
285
case AST_IDENTIFIER: ps(exp->string); break;
286
case EXP_IDENTIFIER: ps(exp->string); break;
287
case EXP_NUMBER: printf("%.9g", exp->number); break;
288
case EXP_STRING: pstr(exp->string); break;
289
case EXP_REGEXP: pregexp(exp->string, exp->number); break;
290
291
case EXP_UNDEF: break;
292
case EXP_NULL: ps("null"); break;
293
case EXP_TRUE: ps("true"); break;
294
case EXP_FALSE: ps("false"); break;
295
case EXP_THIS: ps("this"); break;
296
297
case EXP_OBJECT: pobject(d, exp->a); break;
298
case EXP_ARRAY: parray(d, exp->a); break;
299
300
case EXP_DELETE: puna(d, p, exp, "delete ", ""); break;
301
case EXP_VOID: puna(d, p, exp, "void ", ""); break;
302
case EXP_TYPEOF: puna(d, p, exp, "typeof ", ""); break;
303
case EXP_PREINC: puna(d, p, exp, "++", ""); break;
304
case EXP_PREDEC: puna(d, p, exp, "--", ""); break;
305
case EXP_POSTINC: puna(d, p, exp, "", "++"); break;
306
case EXP_POSTDEC: puna(d, p, exp, "", "--"); break;
307
case EXP_POS: puna(d, p, exp, "+", ""); break;
308
case EXP_NEG: puna(d, p, exp, "-", ""); break;
309
case EXP_BITNOT: puna(d, p, exp, "~", ""); break;
310
case EXP_LOGNOT: puna(d, p, exp, "!", ""); break;
311
312
case EXP_LOGOR: pbin(d, p, exp, " || "); break;
313
case EXP_LOGAND: pbin(d, p, exp, " && "); break;
314
case EXP_BITOR: pbin(d, p, exp, " | "); break;
315
case EXP_BITXOR: pbin(d, p, exp, " ^ "); break;
316
case EXP_BITAND: pbin(d, p, exp, " & "); break;
317
case EXP_EQ: pbin(d, p, exp, " == "); break;
318
case EXP_NE: pbin(d, p, exp, " != "); break;
319
case EXP_STRICTEQ: pbin(d, p, exp, " === "); break;
320
case EXP_STRICTNE: pbin(d, p, exp, " !== "); break;
321
case EXP_LT: pbin(d, p, exp, " < "); break;
322
case EXP_GT: pbin(d, p, exp, " > "); break;
323
case EXP_LE: pbin(d, p, exp, " <= "); break;
324
case EXP_GE: pbin(d, p, exp, " >= "); break;
325
case EXP_INSTANCEOF: pbin(d, p, exp, " instanceof "); break;
326
case EXP_IN: pbin(d, p, exp, " in "); break;
327
case EXP_SHL: pbin(d, p, exp, " << "); break;
328
case EXP_SHR: pbin(d, p, exp, " >> "); break;
329
case EXP_USHR: pbin(d, p, exp, " >>> "); break;
330
case EXP_ADD: pbin(d, p, exp, " + "); break;
331
case EXP_SUB: pbin(d, p, exp, " - "); break;
332
case EXP_MUL: pbin(d, p, exp, " * "); break;
333
case EXP_DIV: pbin(d, p, exp, " / "); break;
334
case EXP_MOD: pbin(d, p, exp, " % "); break;
335
case EXP_ASS: pbin(d, p, exp, " = "); break;
336
case EXP_ASS_MUL: pbin(d, p, exp, " *= "); break;
337
case EXP_ASS_DIV: pbin(d, p, exp, " /= "); break;
338
case EXP_ASS_MOD: pbin(d, p, exp, " %= "); break;
339
case EXP_ASS_ADD: pbin(d, p, exp, " += "); break;
340
case EXP_ASS_SUB: pbin(d, p, exp, " -= "); break;
341
case EXP_ASS_SHL: pbin(d, p, exp, " <<= "); break;
342
case EXP_ASS_SHR: pbin(d, p, exp, " >>= "); break;
343
case EXP_ASS_USHR: pbin(d, p, exp, " >>>= "); break;
344
case EXP_ASS_BITAND: pbin(d, p, exp, " &= "); break;
345
case EXP_ASS_BITXOR: pbin(d, p, exp, " ^= "); break;
346
case EXP_ASS_BITOR: pbin(d, p, exp, " |= "); break;
347
348
case EXP_COMMA: pbin(d, p, exp, ", "); break;
349
350
case EXP_COND:
351
pexpi(d, p, exp->a);
352
ps(" ? ");
353
pexpi(d, p, exp->b);
354
ps(" : ");
355
pexpi(d, p, exp->c);
356
break;
357
358
case EXP_INDEX:
359
pexpi(d, p, exp->a);
360
pc('[');
361
pexpi(d, 0, exp->b);
362
pc(']');
363
break;
364
365
case EXP_MEMBER:
366
pexpi(d, p, exp->a);
367
pc('.');
368
pexpi(d, 0, exp->b);
369
break;
370
371
case EXP_CALL:
372
pexpi(d, p, exp->a);
373
pc('(');
374
pargs(d, exp->b);
375
pc(')');
376
break;
377
378
case EXP_NEW:
379
ps("new ");
380
pexpi(d, p, exp->a);
381
pc('(');
382
pargs(d, exp->b);
383
pc(')');
384
break;
385
386
case EXP_FUN:
387
if (p == 0) pc('(');
388
ps("function ");
389
if (exp->a) pexpi(d, 0, exp->a);
390
pc('(');
391
pargs(d, exp->b);
392
ps(") {\n");
393
pstmlist(d, exp->c);
394
in(d); pc('}');
395
if (p == 0) pc(')');
396
break;
397
398
default:
399
ps("<UNKNOWN>");
400
break;
401
}
402
403
if (paren) pc(')');
404
}
405
406
static void pexp(int d, js_Ast *exp)
407
{
408
pexpi(d, 0, exp);
409
}
410
411
static void pvar(int d, js_Ast *var)
412
{
413
assert(var->type == EXP_VAR);
414
pexp(d, var->a);
415
if (var->b) {
416
ps(" = ");
417
pexp(d, var->b);
418
}
419
}
420
421
static void pvarlist(int d, js_Ast *list)
422
{
423
while (list) {
424
assert(list->type == AST_LIST);
425
pvar(d, list->a);
426
list = list->b;
427
if (list)
428
ps(", ");
429
}
430
}
431
432
static void pblock(int d, js_Ast *block)
433
{
434
assert(block->type == STM_BLOCK);
435
ps(" {\n");
436
pstmlist(d, block->a);
437
in(d); pc('}');
438
}
439
440
static void pstmh(int d, js_Ast *stm)
441
{
442
if (stm->type == STM_BLOCK)
443
pblock(d, stm);
444
else {
445
nl();
446
pstm(d+1, stm);
447
}
448
}
449
450
static void pcaselist(int d, js_Ast *list)
451
{
452
while (list) {
453
js_Ast *stm = list->a;
454
if (stm->type == STM_CASE) {
455
in(d); ps("case "); pexp(d, stm->a); ps(":\n");
456
pstmlist(d, stm->b);
457
}
458
if (stm->type == STM_DEFAULT) {
459
in(d); ps("default:\n");
460
pstmlist(d, stm->a);
461
}
462
list = list->b;
463
}
464
}
465
466
static void pstm(int d, js_Ast *stm)
467
{
468
if (stm->type == STM_BLOCK) {
469
pblock(d, stm);
470
return;
471
}
472
473
in(d);
474
475
switch (stm->type) {
476
case AST_FUNDEC:
477
ps("function ");
478
pexp(d, stm->a);
479
pc('(');
480
pargs(d, stm->b);
481
ps(") {\n");
482
pstmlist(d, stm->c);
483
in(d); ps("}");
484
break;
485
486
case STM_EMPTY:
487
pc(';');
488
break;
489
490
case STM_VAR:
491
ps("var ");
492
pvarlist(d, stm->a);
493
ps(";");
494
break;
495
496
case STM_IF:
497
ps("if ("); pexp(d, stm->a); ps(")");
498
pstmh(d, stm->b);
499
if (stm->c) {
500
nl(); in(d); ps("else");
501
pstmh(d, stm->c);
502
}
503
break;
504
505
case STM_DO:
506
ps("do");
507
pstmh(d, stm->a);
508
nl();
509
in(d); ps("while ("); pexp(d, stm->b); ps(");");
510
break;
511
512
case STM_WHILE:
513
ps("while ("); pexp(d, stm->a); ps(")");
514
pstmh(d, stm->b);
515
break;
516
517
case STM_FOR:
518
ps("for (");
519
pexp(d, stm->a); ps("; ");
520
pexp(d, stm->b); ps("; ");
521
pexp(d, stm->c); ps(")");
522
pstmh(d, stm->d);
523
break;
524
case STM_FOR_VAR:
525
ps("for (var ");
526
pvarlist(d, stm->a); ps("; ");
527
pexp(d, stm->b); ps("; ");
528
pexp(d, stm->c); ps(")");
529
pstmh(d, stm->d);
530
break;
531
case STM_FOR_IN:
532
ps("for (");
533
pexp(d, stm->a); ps(" in ");
534
pexp(d, stm->b); ps(")");
535
pstmh(d, stm->c);
536
break;
537
case STM_FOR_IN_VAR:
538
ps("for (var ");
539
pvarlist(d, stm->a); ps(" in ");
540
pexp(d, stm->b); ps(")");
541
pstmh(d, stm->c);
542
break;
543
544
case STM_CONTINUE:
545
if (stm->a) {
546
ps("continue "); pexp(d, stm->a); ps(";");
547
} else {
548
ps("continue;");
549
}
550
break;
551
552
case STM_BREAK:
553
if (stm->a) {
554
ps("break "); pexp(d, stm->a); ps(";");
555
} else {
556
ps("break;");
557
}
558
break;
559
560
case STM_RETURN:
561
if (stm->a) {
562
ps("return "); pexp(d, stm->a); ps(";");
563
} else {
564
ps("return;");
565
}
566
break;
567
568
case STM_WITH:
569
ps("with ("); pexp(d, stm->a); ps(")");
570
pstmh(d, stm->b);
571
break;
572
573
case STM_SWITCH:
574
ps("switch (");
575
pexp(d, stm->a);
576
ps(") {\n");
577
pcaselist(d, stm->b);
578
in(d); ps("}");
579
break;
580
581
case STM_THROW:
582
ps("throw "); pexp(d, stm->a); ps(";");
583
break;
584
585
case STM_TRY:
586
ps("try");
587
pstmh(d, stm->a);
588
if (stm->b && stm->c) {
589
nl(); in(d); ps("catch ("); pexp(d, stm->b); ps(")");
590
pstmh(d, stm->c);
591
}
592
if (stm->d) {
593
nl(); in(d); ps("finally");
594
pstmh(d, stm->d);
595
}
596
break;
597
598
case STM_LABEL:
599
pexp(d, stm->a); ps(": "); pstm(d, stm->b);
600
break;
601
602
case STM_DEBUGGER:
603
ps("debugger;");
604
break;
605
606
default:
607
pexp(d, stm); pc(';');
608
}
609
}
610
611
static void pstmlist(int d, js_Ast *list)
612
{
613
while (list) {
614
assert(list->type == AST_LIST);
615
pstm(d+1, list->a);
616
nl();
617
list = list->b;
618
}
619
}
620
621
void jsP_dumpsyntax(js_State *J, js_Ast *prog)
622
{
623
if (prog->type == AST_LIST)
624
pstmlist(-1, prog);
625
else {
626
pstm(0, prog);
627
nl();
628
}
629
}
630
631
/* S-expression list representation */
632
633
static void snode(int d, js_Ast *node)
634
{
635
void (*afun)(int,js_Ast*) = snode;
636
void (*bfun)(int,js_Ast*) = snode;
637
void (*cfun)(int,js_Ast*) = snode;
638
void (*dfun)(int,js_Ast*) = snode;
639
640
if (!node) {
641
return;
642
}
643
644
if (node->type == AST_LIST) {
645
slist(d, node);
646
return;
647
}
648
649
pc('(');
650
ps(astname[node->type]);
651
switch (node->type) {
652
case AST_IDENTIFIER: pc(' '); ps(node->string); break;
653
case EXP_IDENTIFIER: pc(' '); ps(node->string); break;
654
case EXP_STRING: pc(' '); pstr(node->string); break;
655
case EXP_REGEXP: pc(' '); pregexp(node->string, node->number); break;
656
case EXP_NUMBER: printf(" %.9g", node->number); break;
657
case STM_BLOCK: afun = sblock; break;
658
case AST_FUNDEC: case EXP_FUN: cfun = sblock; break;
659
case EXP_PROP_GET: cfun = sblock; break;
660
case EXP_PROP_SET: cfun = sblock; break;
661
case STM_SWITCH: bfun = sblock; break;
662
case STM_CASE: bfun = sblock; break;
663
case STM_DEFAULT: afun = sblock; break;
664
}
665
if (node->a) { pc(' '); afun(d, node->a); }
666
if (node->b) { pc(' '); bfun(d, node->b); }
667
if (node->c) { pc(' '); cfun(d, node->c); }
668
if (node->d) { pc(' '); dfun(d, node->d); }
669
pc(')');
670
}
671
672
static void slist(int d, js_Ast *list)
673
{
674
pc('[');
675
while (list) {
676
assert(list->type == AST_LIST);
677
snode(d, list->a);
678
list = list->b;
679
if (list)
680
pc(' ');
681
}
682
pc(']');
683
}
684
685
static void sblock(int d, js_Ast *list)
686
{
687
ps("[\n");
688
in(d+1);
689
while (list) {
690
assert(list->type == AST_LIST);
691
snode(d+1, list->a);
692
list = list->b;
693
if (list) {
694
nl();
695
in(d+1);
696
}
697
}
698
nl(); in(d); pc(']');
699
}
700
701
void jsP_dumplist(js_State *J, js_Ast *prog)
702
{
703
if (prog->type == AST_LIST)
704
sblock(0, prog);
705
else
706
snode(0, prog);
707
nl();
708
}
709
710
/* Compiled code */
711
712
void jsC_dumpfunction(js_State *J, js_Function *F)
713
{
714
js_Instruction *p = F->code;
715
js_Instruction *end = F->code + F->codelen;
716
unsigned int i;
717
718
printf("%s(%d)\n", F->name, F->numparams);
719
if (F->lightweight) printf("\tlightweight\n");
720
if (F->arguments) printf("\targuments\n");
721
printf("\tsource %s:%d\n", F->filename, F->line);
722
for (i = 0; i < F->funlen; ++i)
723
printf("\tfunction %d %s\n", i, F->funtab[i]->name);
724
for (i = 0; i < F->varlen; ++i)
725
printf("\tlocal %d %s\n", i + 1, F->vartab[i]);
726
727
printf("{\n");
728
while (p < end) {
729
int c = *p++;
730
731
printf("% 5d: ", (int)(p - F->code) - 1);
732
ps(opname[c]);
733
734
switch (c) {
735
case OP_NUMBER:
736
printf(" %.9g", F->numtab[*p++]);
737
break;
738
case OP_STRING:
739
pc(' ');
740
pstr(F->strtab[*p++]);
741
break;
742
case OP_NEWREGEXP:
743
pc(' ');
744
pregexp(F->strtab[p[0]], p[1]);
745
p += 2;
746
break;
747
748
case OP_INITVAR:
749
case OP_DEFVAR:
750
case OP_GETVAR:
751
case OP_SETVAR:
752
case OP_DELVAR:
753
case OP_GETPROP_S:
754
case OP_SETPROP_S:
755
case OP_DELPROP_S:
756
case OP_CATCH:
757
pc(' ');
758
ps(F->strtab[*p++]);
759
break;
760
761
case OP_LINE:
762
case OP_CLOSURE:
763
case OP_INITLOCAL:
764
case OP_GETLOCAL:
765
case OP_SETLOCAL:
766
case OP_DELLOCAL:
767
case OP_NUMBER_POS:
768
case OP_NUMBER_NEG:
769
case OP_CALL:
770
case OP_NEW:
771
case OP_JUMP:
772
case OP_JTRUE:
773
case OP_JFALSE:
774
case OP_JCASE:
775
case OP_TRY:
776
printf(" %d", *p++);
777
break;
778
}
779
780
nl();
781
}
782
printf("}\n");
783
784
for (i = 0; i < F->funlen; ++i) {
785
if (F->funtab[i] != F) {
786
printf("function %d ", i);
787
jsC_dumpfunction(J, F->funtab[i]);
788
}
789
}
790
}
791
792
/* Runtime values */
793
794
void js_dumpvalue(js_State *J, js_Value v)
795
{
796
switch (v.type) {
797
case JS_TUNDEFINED: printf("undefined"); break;
798
case JS_TNULL: printf("null"); break;
799
case JS_TBOOLEAN: printf(v.u.boolean ? "true" : "false"); break;
800
case JS_TNUMBER: printf("%.9g", v.u.number); break;
801
case JS_TSHRSTR: printf("'%s'", v.u.shrstr); break;
802
case JS_TLITSTR: printf("'%s'", v.u.litstr); break;
803
case JS_TMEMSTR: printf("'%s'", v.u.memstr->p); break;
804
case JS_TOBJECT:
805
if (v.u.object == J->G) {
806
printf("[Global]");
807
break;
808
}
809
switch (v.u.object->type) {
810
case JS_COBJECT: printf("[Object %p]", v.u.object); break;
811
case JS_CARRAY: printf("[Array %p]", v.u.object); break;
812
case JS_CFUNCTION:
813
printf("[Function %p, %s, %s:%d]",
814
v.u.object,
815
v.u.object->u.f.function->name,
816
v.u.object->u.f.function->filename,
817
v.u.object->u.f.function->line);
818
break;
819
case JS_CSCRIPT: printf("[Script %s]", v.u.object->u.f.function->filename); break;
820
case JS_CCFUNCTION: printf("[CFunction %p]", v.u.object->u.c.function); break;
821
case JS_CBOOLEAN: printf("[Boolean %d]", v.u.object->u.boolean); break;
822
case JS_CNUMBER: printf("[Number %g]", v.u.object->u.number); break;
823
case JS_CSTRING: printf("[String'%s']", v.u.object->u.s.string); break;
824
case JS_CERROR: printf("[Error %s]", v.u.object->u.s.string); break;
825
case JS_CITERATOR: printf("[Iterator %p]", v.u.object); break;
826
case JS_CUSERDATA:
827
printf("[Userdata %s %p]", v.u.object->u.user.tag, v.u.object->u.user.data);
828
break;
829
default: printf("[Object %p]", v.u.object); break;
830
}
831
break;
832
}
833
}
834
835
static void js_dumpproperty(js_State *J, js_Property *node)
836
{
837
if (node->left->level)
838
js_dumpproperty(J, node->left);
839
printf("\t%s: ", node->name);
840
js_dumpvalue(J, node->value);
841
printf(",\n");
842
if (node->right->level)
843
js_dumpproperty(J, node->right);
844
}
845
846
void js_dumpobject(js_State *J, js_Object *obj)
847
{
848
printf("{\n");
849
if (obj->properties->level)
850
js_dumpproperty(J, obj->properties);
851
printf("}\n");
852
}
853
854