52 |
struct IfDirective * next; |
struct IfDirective * next; |
53 |
}; |
}; |
54 |
|
|
55 |
|
bool jscoverage_mozilla = false; |
56 |
|
|
57 |
static bool * exclusive_directives = NULL; |
static bool * exclusive_directives = NULL; |
58 |
|
|
59 |
static JSRuntime * runtime = NULL; |
static JSRuntime * runtime = NULL; |
70 |
static uint16_t num_lines = 0; |
static uint16_t num_lines = 0; |
71 |
|
|
72 |
void jscoverage_set_js_version(const char * version) { |
void jscoverage_set_js_version(const char * version) { |
73 |
js_version = atoi(version); |
js_version = JS_StringToVersion(version); |
74 |
|
if (js_version != JSVERSION_UNKNOWN) { |
75 |
|
return; |
76 |
|
} |
77 |
|
|
78 |
|
char * end; |
79 |
|
js_version = (JSVersion) strtol(version, &end, 10); |
80 |
|
if ((size_t) (end - version) != strlen(version)) { |
81 |
|
fatal("invalid version: %s", version); |
82 |
|
} |
83 |
} |
} |
84 |
|
|
85 |
void jscoverage_init(void) { |
void jscoverage_init(void) { |
267 |
} |
} |
268 |
} |
} |
269 |
|
|
270 |
static void instrument_expression(JSParseNode * node, Stream * f); |
static void output_expression(JSParseNode * node, Stream * f, bool parenthesize_object_literals); |
271 |
static void instrument_statement(JSParseNode * node, Stream * f, int indent, bool is_jscoverage_if); |
static void instrument_statement(JSParseNode * node, Stream * f, int indent, bool is_jscoverage_if); |
272 |
static void output_statement(JSParseNode * node, Stream * f, int indent, bool is_jscoverage_if); |
static void output_statement(JSParseNode * node, Stream * f, int indent, bool is_jscoverage_if); |
273 |
|
|
284 |
Stream_write_string(f, "each "); |
Stream_write_string(f, "each "); |
285 |
} |
} |
286 |
Stream_write_char(f, '('); |
Stream_write_char(f, '('); |
287 |
instrument_expression(node->pn_left, f); |
output_expression(node->pn_left, f, false); |
288 |
Stream_write_char(f, ')'); |
Stream_write_char(f, ')'); |
289 |
} |
} |
290 |
|
|
291 |
|
static void output_array_comprehension_or_generator_expression(JSParseNode * node, Stream * f) { |
292 |
|
assert(node->pn_type == TOK_LEXICALSCOPE); |
293 |
|
assert(node->pn_arity == PN_NAME); |
294 |
|
JSParseNode * for_node = node->pn_expr; |
295 |
|
assert(for_node->pn_type == TOK_FOR); |
296 |
|
assert(for_node->pn_arity == PN_BINARY); |
297 |
|
JSParseNode * p = for_node; |
298 |
|
while (p->pn_type == TOK_FOR) { |
299 |
|
p = p->pn_right; |
300 |
|
} |
301 |
|
JSParseNode * if_node = NULL; |
302 |
|
if (p->pn_type == TOK_IF) { |
303 |
|
if_node = p; |
304 |
|
assert(if_node->pn_arity == PN_TERNARY); |
305 |
|
p = if_node->pn_kid2; |
306 |
|
} |
307 |
|
assert(p->pn_arity == PN_UNARY); |
308 |
|
p = p->pn_kid; |
309 |
|
if (p->pn_type == TOK_YIELD) { |
310 |
|
/* for generator expressions */ |
311 |
|
p = p->pn_kid; |
312 |
|
} |
313 |
|
|
314 |
|
output_expression(p, f, false); |
315 |
|
p = for_node; |
316 |
|
while (p->pn_type == TOK_FOR) { |
317 |
|
Stream_write_char(f, ' '); |
318 |
|
output_for_in(p, f); |
319 |
|
p = p->pn_right; |
320 |
|
} |
321 |
|
if (if_node) { |
322 |
|
Stream_write_string(f, " if ("); |
323 |
|
output_expression(if_node->pn_kid1, f, false); |
324 |
|
Stream_write_char(f, ')'); |
325 |
|
} |
326 |
|
} |
327 |
|
|
328 |
static void instrument_function(JSParseNode * node, Stream * f, int indent, enum FunctionType type) { |
static void instrument_function(JSParseNode * node, Stream * f, int indent, enum FunctionType type) { |
329 |
assert(node->pn_type == TOK_FUNCTION); |
assert(node->pn_type == TOK_FUNCTION); |
330 |
assert(node->pn_arity == PN_FUNC); |
assert(node->pn_arity == PN_FUNC); |
335 |
assert(object == &function->object); |
assert(object == &function->object); |
336 |
Stream_printf(f, "%*s", indent, ""); |
Stream_printf(f, "%*s", indent, ""); |
337 |
if (type == FUNCTION_NORMAL) { |
if (type == FUNCTION_NORMAL) { |
338 |
Stream_write_string(f, "function"); |
Stream_write_string(f, "function "); |
339 |
} |
} |
340 |
|
|
341 |
/* function name */ |
/* function name */ |
342 |
if (function->atom) { |
if (function->atom) { |
|
Stream_write_char(f, ' '); |
|
343 |
print_string_atom(function->atom, f); |
print_string_atom(function->atom, f); |
344 |
} |
} |
345 |
|
|
347 |
function parameters - see JS_DecompileFunction in jsapi.cpp, which calls |
function parameters - see JS_DecompileFunction in jsapi.cpp, which calls |
348 |
js_DecompileFunction in jsopcode.cpp |
js_DecompileFunction in jsopcode.cpp |
349 |
*/ |
*/ |
350 |
Stream_write_string(f, "("); |
Stream_write_char(f, '('); |
351 |
JSArenaPool pool; |
JSArenaPool pool; |
352 |
JS_INIT_ARENA_POOL(&pool, "instrument_function", 256, 1, &context->scriptStackQuota); |
JS_INIT_ARENA_POOL(&pool, "instrument_function", 256, 1, &context->scriptStackQuota); |
353 |
jsuword * local_names = NULL; |
jsuword * local_names = NULL; |
357 |
fatal("out of memory"); |
fatal("out of memory"); |
358 |
} |
} |
359 |
} |
} |
360 |
|
bool destructuring = false; |
361 |
for (int i = 0; i < function->nargs; i++) { |
for (int i = 0; i < function->nargs; i++) { |
362 |
if (i > 0) { |
if (i > 0) { |
363 |
Stream_write_string(f, ", "); |
Stream_write_string(f, ", "); |
364 |
} |
} |
365 |
JSAtom * param = JS_LOCAL_NAME_TO_ATOM(local_names[i]); |
JSAtom * param = JS_LOCAL_NAME_TO_ATOM(local_names[i]); |
366 |
if (param == NULL) { |
if (param == NULL) { |
367 |
fatal("unsupported parameter type for function: %s", file_id); |
destructuring = true; |
368 |
|
JSParseNode * expression = NULL; |
369 |
|
assert(node->pn_body->pn_type == TOK_LC || node->pn_body->pn_type == TOK_BODY); |
370 |
|
JSParseNode * semi = node->pn_body->pn_head; |
371 |
|
assert(semi->pn_type == TOK_SEMI); |
372 |
|
JSParseNode * comma = semi->pn_kid; |
373 |
|
assert(comma->pn_type == TOK_COMMA); |
374 |
|
for (JSParseNode * p = comma->pn_head; p != NULL; p = p->pn_next) { |
375 |
|
assert(p->pn_type == TOK_ASSIGN); |
376 |
|
JSParseNode * rhs = p->pn_right; |
377 |
|
assert(JSSTRING_LENGTH(ATOM_TO_STRING(rhs->pn_atom)) == 0); |
378 |
|
if (rhs->pn_slot == i) { |
379 |
|
expression = p->pn_left; |
380 |
|
break; |
381 |
|
} |
382 |
|
} |
383 |
|
assert(expression != NULL); |
384 |
|
output_expression(expression, f, false); |
385 |
|
} |
386 |
|
else { |
387 |
|
print_string_atom(param, f); |
388 |
} |
} |
|
print_string_atom(param, f); |
|
389 |
} |
} |
390 |
JS_FinishArenaPool(&pool); |
JS_FinishArenaPool(&pool); |
391 |
Stream_write_string(f, ") {\n"); |
Stream_write_string(f, ") {\n"); |
392 |
|
|
393 |
/* function body */ |
/* function body */ |
394 |
if (function->flags & JSFUN_EXPR_CLOSURE) { |
if (function->flags & JSFUN_EXPR_CLOSURE) { |
395 |
/* expression closure */ |
/* expression closure - use output_statement instead of instrument_statement */ |
396 |
output_statement(node->pn_body, f, indent + 2, false); |
if (node->pn_body->pn_type == TOK_BODY) { |
397 |
|
assert(node->pn_body->pn_arity == PN_LIST); |
398 |
|
assert(node->pn_body->pn_count == 2); |
399 |
|
output_statement(node->pn_body->pn_head->pn_next, f, indent + 2, false); |
400 |
|
} |
401 |
|
else { |
402 |
|
output_statement(node->pn_body, f, indent + 2, false); |
403 |
|
} |
404 |
} |
} |
405 |
else { |
else { |
406 |
instrument_statement(node->pn_body, f, indent + 2, false); |
assert(node->pn_body->pn_type == TOK_LC); |
407 |
|
assert(node->pn_body->pn_arity == PN_LIST); |
408 |
|
JSParseNode * p = node->pn_body->pn_head; |
409 |
|
if (destructuring) { |
410 |
|
p = p->pn_next; |
411 |
|
} |
412 |
|
for (; p != NULL; p = p->pn_next) { |
413 |
|
instrument_statement(p, f, indent + 2, false); |
414 |
|
} |
415 |
} |
} |
416 |
|
|
417 |
Stream_write_string(f, "}\n"); |
Stream_write_char(f, '}'); |
418 |
} |
} |
419 |
|
|
420 |
static void instrument_function_call(JSParseNode * node, Stream * f) { |
static void instrument_function_call(JSParseNode * node, Stream * f) { |
428 |
|
|
429 |
if (function_node->pn_flags & TCF_GENEXP_LAMBDA) { |
if (function_node->pn_flags & TCF_GENEXP_LAMBDA) { |
430 |
/* it's a generator expression */ |
/* it's a generator expression */ |
|
JSParseNode * lexical_scope_node = function_node->pn_body; |
|
|
assert(lexical_scope_node->pn_type == TOK_LEXICALSCOPE); |
|
|
assert(lexical_scope_node->pn_arity == PN_NAME); |
|
|
JSParseNode * for_node = lexical_scope_node->pn_body; |
|
|
assert(for_node->pn_type == TOK_FOR); |
|
|
assert(for_node->pn_arity == PN_BINARY); |
|
|
JSParseNode * if_node = NULL; |
|
|
JSParseNode * semi_node; |
|
|
switch (for_node->pn_right->pn_type) { |
|
|
case TOK_SEMI: |
|
|
semi_node = for_node->pn_right; |
|
|
break; |
|
|
case TOK_IF: |
|
|
if_node = for_node->pn_right; |
|
|
assert(if_node->pn_arity == PN_TERNARY); |
|
|
semi_node = if_node->pn_kid2; |
|
|
assert(semi_node->pn_type == TOK_SEMI); |
|
|
break; |
|
|
default: |
|
|
abort(); |
|
|
break; |
|
|
} |
|
|
assert(semi_node->pn_arity == PN_UNARY); |
|
|
JSParseNode * yield_node = semi_node->pn_kid; |
|
|
assert(yield_node->pn_type == TOK_YIELD); |
|
431 |
Stream_write_char(f, '('); |
Stream_write_char(f, '('); |
432 |
instrument_expression(yield_node->pn_kid, f); |
output_array_comprehension_or_generator_expression(function_node->pn_body, f); |
|
Stream_write_char(f, ' '); |
|
|
output_for_in(for_node, f); |
|
|
if (if_node) { |
|
|
Stream_write_string(f, " if ("); |
|
|
instrument_expression(if_node->pn_kid1, f); |
|
|
Stream_write_char(f, ')'); |
|
|
} |
|
433 |
Stream_write_char(f, ')'); |
Stream_write_char(f, ')'); |
434 |
return; |
return; |
435 |
} |
} |
|
else { |
|
|
Stream_write_char(f, '('); |
|
|
instrument_expression(function_node, f); |
|
|
Stream_write_char(f, ')'); |
|
|
} |
|
|
} |
|
|
else { |
|
|
instrument_expression(function_node, f); |
|
436 |
} |
} |
437 |
|
output_expression(function_node, f, false); |
438 |
Stream_write_char(f, '('); |
Stream_write_char(f, '('); |
439 |
for (struct JSParseNode * p = function_node->pn_next; p != NULL; p = p->pn_next) { |
for (struct JSParseNode * p = function_node->pn_next; p != NULL; p = p->pn_next) { |
440 |
if (p != node->pn_head->pn_next) { |
if (p != node->pn_head->pn_next) { |
441 |
Stream_write_string(f, ", "); |
Stream_write_string(f, ", "); |
442 |
} |
} |
443 |
instrument_expression(p, f); |
output_expression(p, f, false); |
444 |
} |
} |
445 |
Stream_write_char(f, ')'); |
Stream_write_char(f, ')'); |
446 |
} |
} |
448 |
static void instrument_declarations(JSParseNode * list, Stream * f) { |
static void instrument_declarations(JSParseNode * list, Stream * f) { |
449 |
assert(list->pn_arity == PN_LIST); |
assert(list->pn_arity == PN_LIST); |
450 |
for (JSParseNode * p = list->pn_head; p != NULL; p = p->pn_next) { |
for (JSParseNode * p = list->pn_head; p != NULL; p = p->pn_next) { |
451 |
switch (p->pn_type) { |
if (p != list->pn_head) { |
452 |
case TOK_NAME: |
Stream_write_string(f, ", "); |
|
assert(p->pn_arity == PN_NAME); |
|
|
if (p != list->pn_head) { |
|
|
Stream_write_string(f, ", "); |
|
|
} |
|
|
print_string_atom(p->pn_atom, f); |
|
|
if (p->pn_expr != NULL) { |
|
|
Stream_write_string(f, " = "); |
|
|
instrument_expression(p->pn_expr, f); |
|
|
} |
|
|
break; |
|
|
case TOK_ASSIGN: |
|
|
case TOK_RB: |
|
|
case TOK_RC: |
|
|
/* destructuring */ |
|
|
instrument_expression(p, f); |
|
|
break; |
|
|
default: |
|
|
abort(); |
|
|
break; |
|
453 |
} |
} |
454 |
|
output_expression(p, f, false); |
455 |
} |
} |
456 |
} |
} |
457 |
|
|
468 |
TOK_INSTANCEOF binary |
TOK_INSTANCEOF binary |
469 |
TOK_IN binary |
TOK_IN binary |
470 |
*/ |
*/ |
471 |
static void instrument_expression(JSParseNode * node, Stream * f) { |
static void output_expression(JSParseNode * node, Stream * f, bool parenthesize_object_literals) { |
472 |
switch (node->pn_type) { |
switch (node->pn_type) { |
473 |
case TOK_FUNCTION: |
case TOK_FUNCTION: |
474 |
|
Stream_write_char(f, '('); |
475 |
instrument_function(node, f, 0, FUNCTION_NORMAL); |
instrument_function(node, f, 0, FUNCTION_NORMAL); |
476 |
|
Stream_write_char(f, ')'); |
477 |
break; |
break; |
478 |
case TOK_COMMA: |
case TOK_COMMA: |
479 |
for (struct JSParseNode * p = node->pn_head; p != NULL; p = p->pn_next) { |
for (struct JSParseNode * p = node->pn_head; p != NULL; p = p->pn_next) { |
480 |
if (p != node->pn_head) { |
if (p != node->pn_head) { |
481 |
Stream_write_string(f, ", "); |
Stream_write_string(f, ", "); |
482 |
} |
} |
483 |
instrument_expression(p, f); |
output_expression(p, f, parenthesize_object_literals); |
484 |
} |
} |
485 |
break; |
break; |
486 |
case TOK_ASSIGN: |
case TOK_ASSIGN: |
487 |
instrument_expression(node->pn_left, f); |
output_expression(node->pn_left, f, parenthesize_object_literals); |
488 |
Stream_write_char(f, ' '); |
Stream_write_char(f, ' '); |
489 |
switch (node->pn_op) { |
switch (node->pn_op) { |
490 |
case JSOP_ADD: |
case JSOP_ADD: |
505 |
break; |
break; |
506 |
} |
} |
507 |
Stream_write_string(f, "= "); |
Stream_write_string(f, "= "); |
508 |
instrument_expression(node->pn_right, f); |
output_expression(node->pn_right, f, false); |
509 |
break; |
break; |
510 |
case TOK_HOOK: |
case TOK_HOOK: |
511 |
instrument_expression(node->pn_kid1, f); |
output_expression(node->pn_kid1, f, parenthesize_object_literals); |
512 |
Stream_write_string(f, "? "); |
Stream_write_string(f, "? "); |
513 |
instrument_expression(node->pn_kid2, f); |
output_expression(node->pn_kid2, f, false); |
514 |
Stream_write_string(f, ": "); |
Stream_write_string(f, ": "); |
515 |
instrument_expression(node->pn_kid3, f); |
output_expression(node->pn_kid3, f, false); |
516 |
break; |
break; |
517 |
case TOK_OR: |
case TOK_OR: |
518 |
case TOK_AND: |
case TOK_AND: |
528 |
case TOK_DIVOP: |
case TOK_DIVOP: |
529 |
switch (node->pn_arity) { |
switch (node->pn_arity) { |
530 |
case PN_BINARY: |
case PN_BINARY: |
531 |
instrument_expression(node->pn_left, f); |
output_expression(node->pn_left, f, parenthesize_object_literals); |
532 |
Stream_printf(f, " %s ", get_op(node->pn_op)); |
Stream_printf(f, " %s ", get_op(node->pn_op)); |
533 |
instrument_expression(node->pn_right, f); |
output_expression(node->pn_right, f, false); |
534 |
break; |
break; |
535 |
case PN_LIST: |
case PN_LIST: |
536 |
for (struct JSParseNode * p = node->pn_head; p != NULL; p = p->pn_next) { |
for (struct JSParseNode * p = node->pn_head; p != NULL; p = p->pn_next) { |
537 |
if (p != node->pn_head) { |
if (p == node->pn_head) { |
538 |
|
output_expression(p, f, parenthesize_object_literals); |
539 |
|
} |
540 |
|
else { |
541 |
Stream_printf(f, " %s ", get_op(node->pn_op)); |
Stream_printf(f, " %s ", get_op(node->pn_op)); |
542 |
|
output_expression(p, f, false); |
543 |
} |
} |
|
instrument_expression(p, f); |
|
544 |
} |
} |
545 |
break; |
break; |
546 |
default: |
default: |
550 |
case TOK_UNARYOP: |
case TOK_UNARYOP: |
551 |
switch (node->pn_op) { |
switch (node->pn_op) { |
552 |
case JSOP_NEG: |
case JSOP_NEG: |
553 |
Stream_write_char(f, '-'); |
Stream_write_string(f, "- "); |
554 |
instrument_expression(node->pn_kid, f); |
output_expression(node->pn_kid, f, false); |
555 |
break; |
break; |
556 |
case JSOP_POS: |
case JSOP_POS: |
557 |
Stream_write_char(f, '+'); |
Stream_write_string(f, "+ "); |
558 |
instrument_expression(node->pn_kid, f); |
output_expression(node->pn_kid, f, false); |
559 |
break; |
break; |
560 |
case JSOP_NOT: |
case JSOP_NOT: |
561 |
Stream_write_char(f, '!'); |
Stream_write_string(f, "! "); |
562 |
instrument_expression(node->pn_kid, f); |
output_expression(node->pn_kid, f, false); |
563 |
break; |
break; |
564 |
case JSOP_BITNOT: |
case JSOP_BITNOT: |
565 |
Stream_write_char(f, '~'); |
Stream_write_string(f, "~ "); |
566 |
instrument_expression(node->pn_kid, f); |
output_expression(node->pn_kid, f, false); |
567 |
break; |
break; |
568 |
case JSOP_TYPEOF: |
case JSOP_TYPEOF: |
569 |
Stream_write_string(f, "typeof "); |
Stream_write_string(f, "typeof "); |
570 |
instrument_expression(node->pn_kid, f); |
output_expression(node->pn_kid, f, false); |
571 |
break; |
break; |
572 |
case JSOP_VOID: |
case JSOP_VOID: |
573 |
Stream_write_string(f, "void "); |
Stream_write_string(f, "void "); |
574 |
instrument_expression(node->pn_kid, f); |
output_expression(node->pn_kid, f, false); |
575 |
break; |
break; |
576 |
default: |
default: |
577 |
abort(); |
fatal_source(file_id, node->pn_pos.begin.lineno, "unknown operator (%d)", node->pn_op); |
578 |
break; |
break; |
579 |
} |
} |
580 |
break; |
break; |
588 |
case JSOP_INCPROP: |
case JSOP_INCPROP: |
589 |
case JSOP_INCELEM: |
case JSOP_INCELEM: |
590 |
Stream_write_string(f, "++"); |
Stream_write_string(f, "++"); |
591 |
instrument_expression(node->pn_kid, f); |
output_expression(node->pn_kid, f, false); |
592 |
break; |
break; |
593 |
case JSOP_DECNAME: |
case JSOP_DECNAME: |
594 |
case JSOP_DECPROP: |
case JSOP_DECPROP: |
595 |
case JSOP_DECELEM: |
case JSOP_DECELEM: |
596 |
Stream_write_string(f, "--"); |
Stream_write_string(f, "--"); |
597 |
instrument_expression(node->pn_kid, f); |
output_expression(node->pn_kid, f, false); |
598 |
break; |
break; |
599 |
case JSOP_NAMEINC: |
case JSOP_NAMEINC: |
600 |
case JSOP_PROPINC: |
case JSOP_PROPINC: |
601 |
case JSOP_ELEMINC: |
case JSOP_ELEMINC: |
602 |
instrument_expression(node->pn_kid, f); |
output_expression(node->pn_kid, f, parenthesize_object_literals); |
603 |
Stream_write_string(f, "++"); |
Stream_write_string(f, "++"); |
604 |
break; |
break; |
605 |
case JSOP_NAMEDEC: |
case JSOP_NAMEDEC: |
606 |
case JSOP_PROPDEC: |
case JSOP_PROPDEC: |
607 |
case JSOP_ELEMDEC: |
case JSOP_ELEMDEC: |
608 |
instrument_expression(node->pn_kid, f); |
output_expression(node->pn_kid, f, parenthesize_object_literals); |
609 |
Stream_write_string(f, "--"); |
Stream_write_string(f, "--"); |
610 |
break; |
break; |
611 |
default: |
default: |
619 |
break; |
break; |
620 |
case TOK_DELETE: |
case TOK_DELETE: |
621 |
Stream_write_string(f, "delete "); |
Stream_write_string(f, "delete "); |
622 |
instrument_expression(node->pn_kid, f); |
output_expression(node->pn_kid, f, false); |
623 |
break; |
break; |
624 |
case TOK_DOT: |
case TOK_DOT: |
625 |
|
/* numeric literals must be parenthesized */ |
626 |
|
switch (node->pn_expr->pn_type) { |
627 |
|
case TOK_NUMBER: |
628 |
|
Stream_write_char(f, '('); |
629 |
|
output_expression(node->pn_expr, f, false); |
630 |
|
Stream_write_char(f, ')'); |
631 |
|
break; |
632 |
|
default: |
633 |
|
output_expression(node->pn_expr, f, true); |
634 |
|
break; |
635 |
|
} |
636 |
/* |
/* |
637 |
This may have originally been x['foo-bar']. Because the string 'foo-bar' |
This may have originally been x['foo-bar']. Because the string 'foo-bar' |
638 |
contains illegal characters, we have to use the subscript syntax instead of |
contains illegal characters, we have to use the subscript syntax instead of |
639 |
the dot syntax. |
the dot syntax. |
640 |
*/ |
*/ |
|
instrument_expression(node->pn_expr, f); |
|
641 |
assert(ATOM_IS_STRING(node->pn_atom)); |
assert(ATOM_IS_STRING(node->pn_atom)); |
642 |
{ |
{ |
643 |
JSString * s = ATOM_TO_STRING(node->pn_atom); |
JSString * s = ATOM_TO_STRING(node->pn_atom); |
666 |
} |
} |
667 |
break; |
break; |
668 |
case TOK_LB: |
case TOK_LB: |
669 |
instrument_expression(node->pn_left, f); |
output_expression(node->pn_left, f, false); |
670 |
Stream_write_char(f, '['); |
Stream_write_char(f, '['); |
671 |
instrument_expression(node->pn_right, f); |
output_expression(node->pn_right, f, false); |
672 |
Stream_write_char(f, ']'); |
Stream_write_char(f, ']'); |
673 |
break; |
break; |
674 |
case TOK_LP: |
case TOK_LP: |
682 |
} |
} |
683 |
/* TOK_COMMA is a special case: a hole in the array */ |
/* TOK_COMMA is a special case: a hole in the array */ |
684 |
if (p->pn_type != TOK_COMMA) { |
if (p->pn_type != TOK_COMMA) { |
685 |
instrument_expression(p, f); |
output_expression(p, f, false); |
686 |
} |
} |
687 |
} |
} |
688 |
if (node->pn_extra == PNX_ENDCOMMA) { |
if (node->pn_extra == PNX_ENDCOMMA) { |
691 |
Stream_write_char(f, ']'); |
Stream_write_char(f, ']'); |
692 |
break; |
break; |
693 |
case TOK_RC: |
case TOK_RC: |
694 |
|
if (parenthesize_object_literals) { |
695 |
|
Stream_write_char(f, '('); |
696 |
|
} |
697 |
Stream_write_char(f, '{'); |
Stream_write_char(f, '{'); |
698 |
for (struct JSParseNode * p = node->pn_head; p != NULL; p = p->pn_next) { |
for (struct JSParseNode * p = node->pn_head; p != NULL; p = p->pn_next) { |
699 |
assert(p->pn_type == TOK_COLON); |
if (p->pn_type != TOK_COLON) { |
700 |
|
fatal_source(file_id, p->pn_pos.begin.lineno, "unsupported node type (%d)", p->pn_type); |
701 |
|
} |
702 |
if (p != node->pn_head) { |
if (p != node->pn_head) { |
703 |
Stream_write_string(f, ", "); |
Stream_write_string(f, ", "); |
704 |
} |
} |
713 |
else { |
else { |
714 |
Stream_write_string(f, "set "); |
Stream_write_string(f, "set "); |
715 |
} |
} |
716 |
instrument_expression(p->pn_left, f); |
output_expression(p->pn_left, f, false); |
717 |
if (p->pn_right->pn_type != TOK_FUNCTION) { |
if (p->pn_right->pn_type != TOK_FUNCTION) { |
718 |
fatal("parse error: expected function"); |
fatal_source(file_id, p->pn_pos.begin.lineno, "expected function"); |
719 |
} |
} |
720 |
instrument_function(p->pn_right, f, 0, FUNCTION_GETTER_OR_SETTER); |
instrument_function(p->pn_right, f, 0, FUNCTION_GETTER_OR_SETTER); |
721 |
break; |
break; |
722 |
default: |
default: |
723 |
instrument_expression(p->pn_left, f); |
output_expression(p->pn_left, f, false); |
724 |
Stream_write_string(f, ": "); |
Stream_write_string(f, ": "); |
725 |
instrument_expression(p->pn_right, f); |
output_expression(p->pn_right, f, false); |
726 |
break; |
break; |
727 |
} |
} |
728 |
} |
} |
729 |
Stream_write_char(f, '}'); |
Stream_write_char(f, '}'); |
730 |
|
if (parenthesize_object_literals) { |
731 |
|
Stream_write_char(f, ')'); |
732 |
|
} |
733 |
break; |
break; |
734 |
case TOK_RP: |
case TOK_RP: |
735 |
Stream_write_char(f, '('); |
Stream_write_char(f, '('); |
736 |
instrument_expression(node->pn_kid, f); |
output_expression(node->pn_kid, f, false); |
737 |
Stream_write_char(f, ')'); |
Stream_write_char(f, ')'); |
738 |
break; |
break; |
739 |
case TOK_NAME: |
case TOK_NAME: |
740 |
print_string_atom(node->pn_atom, f); |
print_string_atom(node->pn_atom, f); |
741 |
|
if (node->pn_expr != NULL) { |
742 |
|
Stream_write_string(f, " = "); |
743 |
|
output_expression(node->pn_expr, f, false); |
744 |
|
} |
745 |
break; |
break; |
746 |
case TOK_STRING: |
case TOK_STRING: |
747 |
print_quoted_string_atom(node->pn_atom, f); |
print_quoted_string_atom(node->pn_atom, f); |
789 |
} |
} |
790 |
break; |
break; |
791 |
case TOK_INSTANCEOF: |
case TOK_INSTANCEOF: |
792 |
instrument_expression(node->pn_left, f); |
output_expression(node->pn_left, f, parenthesize_object_literals); |
793 |
Stream_write_string(f, " instanceof "); |
Stream_write_string(f, " instanceof "); |
794 |
instrument_expression(node->pn_right, f); |
output_expression(node->pn_right, f, false); |
795 |
break; |
break; |
796 |
case TOK_IN: |
case TOK_IN: |
797 |
instrument_expression(node->pn_left, f); |
output_expression(node->pn_left, f, false); |
798 |
Stream_write_string(f, " in "); |
Stream_write_string(f, " in "); |
799 |
instrument_expression(node->pn_right, f); |
output_expression(node->pn_right, f, false); |
800 |
break; |
break; |
801 |
case TOK_LEXICALSCOPE: |
case TOK_LEXICALSCOPE: |
802 |
assert(node->pn_arity == PN_NAME); |
assert(node->pn_arity == PN_NAME); |
807 |
assert(node->pn_expr->pn_left->pn_arity == PN_LIST); |
assert(node->pn_expr->pn_left->pn_arity == PN_LIST); |
808 |
instrument_declarations(node->pn_expr->pn_left, f); |
instrument_declarations(node->pn_expr->pn_left, f); |
809 |
Stream_write_string(f, ") "); |
Stream_write_string(f, ") "); |
810 |
instrument_expression(node->pn_expr->pn_right, f); |
output_expression(node->pn_expr->pn_right, f, true); |
811 |
break; |
break; |
812 |
case TOK_YIELD: |
case TOK_YIELD: |
813 |
assert(node->pn_arity == PN_UNARY); |
assert(node->pn_arity == PN_UNARY); |
814 |
Stream_write_string(f, "yield "); |
Stream_write_string(f, "yield"); |
815 |
instrument_expression(node->pn_kid, f); |
if (node->pn_kid != NULL) { |
816 |
|
Stream_write_char(f, ' '); |
817 |
|
output_expression(node->pn_kid, f, true); |
818 |
|
} |
819 |
break; |
break; |
820 |
case TOK_ARRAYCOMP: |
case TOK_ARRAYCOMP: |
821 |
assert(node->pn_arity == PN_LIST); |
assert(node->pn_arity == PN_LIST); |
832 |
abort(); |
abort(); |
833 |
break; |
break; |
834 |
} |
} |
|
assert(block_node->pn_type == TOK_LEXICALSCOPE); |
|
|
assert(block_node->pn_arity == PN_NAME); |
|
|
JSParseNode * for_node = block_node->pn_expr; |
|
|
assert(for_node->pn_type == TOK_FOR); |
|
|
assert(for_node->pn_arity == PN_BINARY); |
|
|
JSParseNode * if_node = NULL; |
|
|
JSParseNode * push_node; |
|
|
switch (for_node->pn_right->pn_type) { |
|
|
case TOK_ARRAYPUSH: |
|
|
push_node = for_node->pn_right; |
|
|
assert(push_node->pn_arity == PN_UNARY); |
|
|
break; |
|
|
case TOK_IF: |
|
|
if_node = for_node->pn_right; |
|
|
assert(if_node->pn_arity == PN_TERNARY); |
|
|
push_node = if_node->pn_kid2; |
|
|
break; |
|
|
default: |
|
|
abort(); |
|
|
break; |
|
|
} |
|
835 |
Stream_write_char(f, '['); |
Stream_write_char(f, '['); |
836 |
instrument_expression(push_node->pn_kid, f); |
output_array_comprehension_or_generator_expression(block_node, f); |
|
Stream_write_char(f, ' '); |
|
|
output_for_in(for_node, f); |
|
|
if (if_node) { |
|
|
Stream_write_string(f, " if ("); |
|
|
instrument_expression(if_node->pn_kid1, f); |
|
|
Stream_write_char(f, ')'); |
|
|
} |
|
837 |
Stream_write_char(f, ']'); |
Stream_write_char(f, ']'); |
838 |
} |
} |
839 |
break; |
break; |
848 |
instrument_declarations(node, f); |
instrument_declarations(node, f); |
849 |
break; |
break; |
850 |
default: |
default: |
851 |
fatal("unsupported node type in file %s: %d", file_id, node->pn_type); |
fatal_source(file_id, node->pn_pos.begin.lineno, "unsupported node type (%d)", node->pn_type); |
852 |
} |
} |
853 |
} |
} |
854 |
|
|
856 |
switch (node->pn_type) { |
switch (node->pn_type) { |
857 |
case TOK_FUNCTION: |
case TOK_FUNCTION: |
858 |
instrument_function(node, f, indent, FUNCTION_NORMAL); |
instrument_function(node, f, indent, FUNCTION_NORMAL); |
859 |
|
Stream_write_char(f, '\n'); |
860 |
break; |
break; |
861 |
case TOK_LC: |
case TOK_LC: |
862 |
assert(node->pn_arity == PN_LIST); |
assert(node->pn_arity == PN_LIST); |
878 |
uint16_t line = node->pn_pos.begin.lineno; |
uint16_t line = node->pn_pos.begin.lineno; |
879 |
if (! is_jscoverage_if) { |
if (! is_jscoverage_if) { |
880 |
if (line > num_lines) { |
if (line > num_lines) { |
881 |
fatal("%s: script contains more than 65,535 lines", file_id); |
fatal("file %s contains more than 65,535 lines", file_id); |
882 |
} |
} |
883 |
if (line >= 2 && exclusive_directives[line - 2]) { |
if (line >= 2 && exclusive_directives[line - 2]) { |
884 |
is_jscoverage_if = true; |
is_jscoverage_if = true; |
887 |
|
|
888 |
Stream_printf(f, "%*s", indent, ""); |
Stream_printf(f, "%*s", indent, ""); |
889 |
Stream_write_string(f, "if ("); |
Stream_write_string(f, "if ("); |
890 |
instrument_expression(node->pn_kid1, f); |
output_expression(node->pn_kid1, f, false); |
891 |
Stream_write_string(f, ") {\n"); |
Stream_write_string(f, ") {\n"); |
892 |
if (is_jscoverage_if && node->pn_kid3) { |
if (is_jscoverage_if && node->pn_kid3) { |
893 |
uint16_t else_start = node->pn_kid3->pn_pos.begin.lineno; |
uint16_t else_start = node->pn_kid3->pn_pos.begin.lineno; |
924 |
assert(node->pn_arity == PN_BINARY); |
assert(node->pn_arity == PN_BINARY); |
925 |
Stream_printf(f, "%*s", indent, ""); |
Stream_printf(f, "%*s", indent, ""); |
926 |
Stream_write_string(f, "switch ("); |
Stream_write_string(f, "switch ("); |
927 |
instrument_expression(node->pn_left, f); |
output_expression(node->pn_left, f, false); |
928 |
Stream_write_string(f, ") {\n"); |
Stream_write_string(f, ") {\n"); |
929 |
{ |
{ |
930 |
JSParseNode * list = node->pn_right; |
JSParseNode * list = node->pn_right; |
936 |
switch (p->pn_type) { |
switch (p->pn_type) { |
937 |
case TOK_CASE: |
case TOK_CASE: |
938 |
Stream_write_string(f, "case "); |
Stream_write_string(f, "case "); |
939 |
instrument_expression(p->pn_left, f); |
output_expression(p->pn_left, f, false); |
940 |
Stream_write_string(f, ":\n"); |
Stream_write_string(f, ":\n"); |
941 |
break; |
break; |
942 |
case TOK_DEFAULT: |
case TOK_DEFAULT: |
960 |
assert(node->pn_arity == PN_BINARY); |
assert(node->pn_arity == PN_BINARY); |
961 |
Stream_printf(f, "%*s", indent, ""); |
Stream_printf(f, "%*s", indent, ""); |
962 |
Stream_write_string(f, "while ("); |
Stream_write_string(f, "while ("); |
963 |
instrument_expression(node->pn_left, f); |
output_expression(node->pn_left, f, false); |
964 |
Stream_write_string(f, ") {\n"); |
Stream_write_string(f, ") {\n"); |
965 |
instrument_statement(node->pn_right, f, indent + 2, false); |
instrument_statement(node->pn_right, f, indent + 2, false); |
966 |
Stream_write_string(f, "}\n"); |
Stream_write_string(f, "}\n"); |
973 |
Stream_write_string(f, "}\n"); |
Stream_write_string(f, "}\n"); |
974 |
Stream_printf(f, "%*s", indent, ""); |
Stream_printf(f, "%*s", indent, ""); |
975 |
Stream_write_string(f, "while ("); |
Stream_write_string(f, "while ("); |
976 |
instrument_expression(node->pn_right, f); |
output_expression(node->pn_right, f, false); |
977 |
Stream_write_string(f, ");\n"); |
Stream_write_string(f, ");\n"); |
978 |
break; |
break; |
979 |
case TOK_FOR: |
case TOK_FOR: |
990 |
assert(node->pn_left->pn_arity == PN_TERNARY); |
assert(node->pn_left->pn_arity == PN_TERNARY); |
991 |
Stream_write_string(f, "for ("); |
Stream_write_string(f, "for ("); |
992 |
if (node->pn_left->pn_kid1) { |
if (node->pn_left->pn_kid1) { |
993 |
instrument_expression(node->pn_left->pn_kid1, f); |
output_expression(node->pn_left->pn_kid1, f, false); |
994 |
} |
} |
995 |
Stream_write_string(f, ";"); |
Stream_write_string(f, ";"); |
996 |
if (node->pn_left->pn_kid2) { |
if (node->pn_left->pn_kid2) { |
997 |
Stream_write_char(f, ' '); |
Stream_write_char(f, ' '); |
998 |
instrument_expression(node->pn_left->pn_kid2, f); |
output_expression(node->pn_left->pn_kid2, f, false); |
999 |
} |
} |
1000 |
Stream_write_string(f, ";"); |
Stream_write_string(f, ";"); |
1001 |
if (node->pn_left->pn_kid3) { |
if (node->pn_left->pn_kid3) { |
1002 |
Stream_write_char(f, ' '); |
Stream_write_char(f, ' '); |
1003 |
instrument_expression(node->pn_left->pn_kid3, f); |
output_expression(node->pn_left->pn_kid3, f, false); |
1004 |
} |
} |
1005 |
Stream_write_char(f, ')'); |
Stream_write_char(f, ')'); |
1006 |
break; |
break; |
1016 |
assert(node->pn_arity == PN_UNARY); |
assert(node->pn_arity == PN_UNARY); |
1017 |
Stream_printf(f, "%*s", indent, ""); |
Stream_printf(f, "%*s", indent, ""); |
1018 |
Stream_write_string(f, "throw "); |
Stream_write_string(f, "throw "); |
1019 |
instrument_expression(node->pn_u.unary.kid, f); |
output_expression(node->pn_u.unary.kid, f, false); |
1020 |
Stream_write_string(f, ";\n"); |
Stream_write_string(f, ";\n"); |
1021 |
break; |
break; |
1022 |
case TOK_TRY: |
case TOK_TRY: |
1033 |
assert(catch->pn_type == TOK_CATCH); |
assert(catch->pn_type == TOK_CATCH); |
1034 |
Stream_printf(f, "%*s", indent, ""); |
Stream_printf(f, "%*s", indent, ""); |
1035 |
Stream_write_string(f, "catch ("); |
Stream_write_string(f, "catch ("); |
1036 |
/* this may not be a name - destructuring assignment */ |
output_expression(catch->pn_kid1, f, false); |
|
/* |
|
|
assert(catch->pn_kid1->pn_arity == PN_NAME); |
|
|
print_string_atom(catch->pn_kid1->pn_atom, f); |
|
|
*/ |
|
|
instrument_expression(catch->pn_kid1, f); |
|
1037 |
if (catch->pn_kid2) { |
if (catch->pn_kid2) { |
1038 |
Stream_write_string(f, " if "); |
Stream_write_string(f, " if "); |
1039 |
instrument_expression(catch->pn_kid2, f); |
output_expression(catch->pn_kid2, f, false); |
1040 |
} |
} |
1041 |
Stream_write_string(f, ") {\n"); |
Stream_write_string(f, ") {\n"); |
1042 |
instrument_statement(catch->pn_kid3, f, indent + 2, false); |
instrument_statement(catch->pn_kid3, f, indent + 2, false); |
1071 |
assert(node->pn_arity == PN_BINARY); |
assert(node->pn_arity == PN_BINARY); |
1072 |
Stream_printf(f, "%*s", indent, ""); |
Stream_printf(f, "%*s", indent, ""); |
1073 |
Stream_write_string(f, "with ("); |
Stream_write_string(f, "with ("); |
1074 |
instrument_expression(node->pn_left, f); |
output_expression(node->pn_left, f, false); |
1075 |
Stream_write_string(f, ") {\n"); |
Stream_write_string(f, ") {\n"); |
1076 |
instrument_statement(node->pn_right, f, indent + 2, false); |
instrument_statement(node->pn_right, f, indent + 2, false); |
1077 |
Stream_printf(f, "%*s", indent, ""); |
Stream_printf(f, "%*s", indent, ""); |
1079 |
break; |
break; |
1080 |
case TOK_VAR: |
case TOK_VAR: |
1081 |
Stream_printf(f, "%*s", indent, ""); |
Stream_printf(f, "%*s", indent, ""); |
1082 |
instrument_expression(node, f); |
output_expression(node, f, false); |
1083 |
Stream_write_string(f, ";\n"); |
Stream_write_string(f, ";\n"); |
1084 |
break; |
break; |
1085 |
case TOK_RETURN: |
case TOK_RETURN: |
1088 |
Stream_write_string(f, "return"); |
Stream_write_string(f, "return"); |
1089 |
if (node->pn_kid != NULL) { |
if (node->pn_kid != NULL) { |
1090 |
Stream_write_char(f, ' '); |
Stream_write_char(f, ' '); |
1091 |
instrument_expression(node->pn_kid, f); |
output_expression(node->pn_kid, f, true); |
1092 |
} |
} |
1093 |
Stream_write_string(f, ";\n"); |
Stream_write_string(f, ";\n"); |
1094 |
break; |
break; |
1096 |
assert(node->pn_arity == PN_UNARY); |
assert(node->pn_arity == PN_UNARY); |
1097 |
Stream_printf(f, "%*s", indent, ""); |
Stream_printf(f, "%*s", indent, ""); |
1098 |
if (node->pn_kid != NULL) { |
if (node->pn_kid != NULL) { |
1099 |
instrument_expression(node->pn_kid, f); |
output_expression(node->pn_kid, f, true); |
1100 |
} |
} |
1101 |
Stream_write_string(f, ";\n"); |
Stream_write_string(f, ";\n"); |
1102 |
break; |
break; |
1103 |
case TOK_COLON: |
case TOK_COLON: |
1104 |
|
{ |
1105 |
assert(node->pn_arity == PN_NAME); |
assert(node->pn_arity == PN_NAME); |
|
/* |
|
|
This one is tricky: can't output instrumentation between the label and the |
|
|
statement it's supposed to label ... |
|
|
*/ |
|
1106 |
Stream_printf(f, "%*s", indent < 2? 0: indent - 2, ""); |
Stream_printf(f, "%*s", indent < 2? 0: indent - 2, ""); |
1107 |
print_string_atom(node->pn_atom, f); |
print_string_atom(node->pn_atom, f); |
1108 |
Stream_write_string(f, ":\n"); |
Stream_write_string(f, ":\n"); |
1109 |
/* |
JSParseNode * labelled = node->pn_expr; |
1110 |
... use output_statement instead of instrument_statement. |
if (labelled->pn_type == TOK_LEXICALSCOPE) { |
1111 |
*/ |
labelled = labelled->pn_expr; |
1112 |
output_statement(node->pn_expr, f, indent, false); |
} |
1113 |
|
if (labelled->pn_type == TOK_LC) { |
1114 |
|
/* labelled block */ |
1115 |
|
Stream_printf(f, "%*s", indent, ""); |
1116 |
|
Stream_write_string(f, "{\n"); |
1117 |
|
instrument_statement(labelled, f, indent + 2, false); |
1118 |
|
Stream_printf(f, "%*s", indent, ""); |
1119 |
|
Stream_write_string(f, "}\n"); |
1120 |
|
} |
1121 |
|
else { |
1122 |
|
/* |
1123 |
|
This one is tricky: can't output instrumentation between the label and the |
1124 |
|
statement it's supposed to label, so use output_statement instead of |
1125 |
|
instrument_statement. |
1126 |
|
*/ |
1127 |
|
output_statement(labelled, f, indent, false); |
1128 |
|
} |
1129 |
break; |
break; |
1130 |
|
} |
1131 |
case TOK_LEXICALSCOPE: |
case TOK_LEXICALSCOPE: |
1132 |
/* let statement */ |
/* let statement */ |
1133 |
assert(node->pn_arity == PN_NAME); |
assert(node->pn_arity == PN_NAME); |
1170 |
case PN_LIST: |
case PN_LIST: |
1171 |
/* let definition */ |
/* let definition */ |
1172 |
Stream_printf(f, "%*s", indent, ""); |
Stream_printf(f, "%*s", indent, ""); |
1173 |
instrument_expression(node, f); |
output_expression(node, f, false); |
1174 |
Stream_write_string(f, ";\n"); |
Stream_write_string(f, ";\n"); |
1175 |
break; |
break; |
1176 |
default: |
default: |
1183 |
Stream_write_string(f, "debugger;\n"); |
Stream_write_string(f, "debugger;\n"); |
1184 |
break; |
break; |
1185 |
default: |
default: |
1186 |
fatal("unsupported node type in file %s: %d", file_id, node->pn_type); |
fatal_source(file_id, node->pn_pos.begin.lineno, "unsupported node type (%d)", node->pn_type); |
1187 |
} |
} |
1188 |
} |
} |
1189 |
|
|
1196 |
if (node->pn_type != TOK_LC && node->pn_type != TOK_LEXICALSCOPE) { |
if (node->pn_type != TOK_LC && node->pn_type != TOK_LEXICALSCOPE) { |
1197 |
uint16_t line = node->pn_pos.begin.lineno; |
uint16_t line = node->pn_pos.begin.lineno; |
1198 |
if (line > num_lines) { |
if (line > num_lines) { |
1199 |
fatal("%s: script contains more than 65,535 lines", file_id); |
fatal("file %s contains more than 65,535 lines", file_id); |
1200 |
} |
} |
1201 |
|
|
1202 |
/* the root node has line number 0 */ |
/* the root node has line number 0 */ |
1244 |
} |
} |
1245 |
|
|
1246 |
static void error_reporter(JSContext * context, const char * message, JSErrorReport * report) { |
static void error_reporter(JSContext * context, const char * message, JSErrorReport * report) { |
1247 |
fprintf(stderr, "jscoverage: parse error: line %u: %s\n", report->lineno, message); |
warn_source(file_id, report->lineno, "%s", message); |
1248 |
} |
} |
1249 |
|
|
1250 |
void jscoverage_instrument_js(const char * id, const uint16_t * characters, size_t num_characters, Stream * output) { |
void jscoverage_instrument_js(const char * id, const uint16_t * characters, size_t num_characters, Stream * output) { |
1253 |
/* parse the javascript */ |
/* parse the javascript */ |
1254 |
JSParseContext parse_context; |
JSParseContext parse_context; |
1255 |
if (! js_InitParseContext(context, &parse_context, NULL, NULL, characters, num_characters, NULL, NULL, 1)) { |
if (! js_InitParseContext(context, &parse_context, NULL, NULL, characters, num_characters, NULL, NULL, 1)) { |
1256 |
fatal("cannot create token stream from file: %s", file_id); |
fatal("cannot create token stream from file %s", file_id); |
1257 |
} |
} |
1258 |
JSErrorReporter old_error_reporter = JS_SetErrorReporter(context, error_reporter); |
JSErrorReporter old_error_reporter = JS_SetErrorReporter(context, error_reporter); |
1259 |
JSParseNode * node = js_ParseScript(context, global, &parse_context); |
JSParseNode * node = js_ParseScript(context, global, &parse_context); |
1260 |
if (node == NULL) { |
if (node == NULL) { |
1261 |
js_ReportUncaughtException(context); |
js_ReportUncaughtException(context); |
1262 |
fatal("parse error in file: %s", file_id); |
fatal("parse error in file %s", file_id); |
1263 |
} |
} |
1264 |
JS_SetErrorReporter(context, old_error_reporter); |
JS_SetErrorReporter(context, old_error_reporter); |
1265 |
num_lines = node->pn_pos.end.lineno; |
num_lines = node->pn_pos.end.lineno; |
1280 |
size_t i = 0; |
size_t i = 0; |
1281 |
while (i < num_characters) { |
while (i < num_characters) { |
1282 |
if (line_number == UINT16_MAX) { |
if (line_number == UINT16_MAX) { |
1283 |
fatal("%s: script has more than 65,535 lines", file_id); |
fatal("file %s contains more than 65,535 lines", file_id); |
1284 |
} |
} |
1285 |
line_number++; |
line_number++; |
1286 |
size_t line_start = i; |
size_t line_start = i; |
1347 |
|
|
1348 |
/* write line number info to the output */ |
/* write line number info to the output */ |
1349 |
Stream_write_string(output, "/* automatically generated by JSCoverage - do not edit */\n"); |
Stream_write_string(output, "/* automatically generated by JSCoverage - do not edit */\n"); |
1350 |
Stream_write_string(output, "if (! top._$jscoverage) {\n top._$jscoverage = {};\n}\n"); |
if (jscoverage_mozilla) { |
1351 |
Stream_write_string(output, "var _$jscoverage = top._$jscoverage;\n"); |
Stream_write_string(output, "try {\n"); |
1352 |
|
Stream_write_string(output, " Components.utils.import('resource://gre/modules/jscoverage.jsm');\n"); |
1353 |
|
Stream_printf(output, " dump('%s: successfully imported jscoverage module\\n');\n", id); |
1354 |
|
Stream_write_string(output, "}\n"); |
1355 |
|
Stream_write_string(output, "catch (e) {\n"); |
1356 |
|
Stream_write_string(output, " _$jscoverage = {};\n"); |
1357 |
|
Stream_printf(output, " dump('%s: failed to import jscoverage module - coverage not available for this file\\n');\n", id); |
1358 |
|
Stream_write_string(output, "}\n"); |
1359 |
|
} |
1360 |
|
else { |
1361 |
|
Stream_write_string(output, "if (! top._$jscoverage) {\n top._$jscoverage = {};\n}\n"); |
1362 |
|
Stream_write_string(output, "var _$jscoverage = top._$jscoverage;\n"); |
1363 |
|
} |
1364 |
Stream_printf(output, "if (! _$jscoverage['%s']) {\n", file_id); |
Stream_printf(output, "if (! _$jscoverage['%s']) {\n", file_id); |
1365 |
Stream_printf(output, " _$jscoverage['%s'] = [];\n", file_id); |
Stream_printf(output, " _$jscoverage['%s'] = [];\n", file_id); |
1366 |
for (int i = 0; i < num_lines; i++) { |
for (int i = 0; i < num_lines; i++) { |