22 |
#include "instrument-js.h" |
#include "instrument-js.h" |
23 |
|
|
24 |
#include <assert.h> |
#include <assert.h> |
25 |
|
#include <math.h> |
26 |
#include <stdlib.h> |
#include <stdlib.h> |
27 |
#include <string.h> |
#include <string.h> |
28 |
|
|
268 |
} |
} |
269 |
} |
} |
270 |
|
|
271 |
static void instrument_expression(JSParseNode * node, Stream * f); |
static void output_expression(JSParseNode * node, Stream * f, bool parenthesize_object_literals); |
272 |
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); |
273 |
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); |
274 |
|
|
285 |
Stream_write_string(f, "each "); |
Stream_write_string(f, "each "); |
286 |
} |
} |
287 |
Stream_write_char(f, '('); |
Stream_write_char(f, '('); |
288 |
instrument_expression(node->pn_left, f); |
output_expression(node->pn_left, f, false); |
289 |
Stream_write_char(f, ')'); |
Stream_write_char(f, ')'); |
290 |
} |
} |
291 |
|
|
312 |
p = p->pn_kid; |
p = p->pn_kid; |
313 |
} |
} |
314 |
|
|
315 |
instrument_expression(p, f); |
output_expression(p, f, false); |
316 |
p = for_node; |
p = for_node; |
317 |
while (p->pn_type == TOK_FOR) { |
while (p->pn_type == TOK_FOR) { |
318 |
Stream_write_char(f, ' '); |
Stream_write_char(f, ' '); |
321 |
} |
} |
322 |
if (if_node) { |
if (if_node) { |
323 |
Stream_write_string(f, " if ("); |
Stream_write_string(f, " if ("); |
324 |
instrument_expression(if_node->pn_kid1, f); |
output_expression(if_node->pn_kid1, f, false); |
325 |
Stream_write_char(f, ')'); |
Stream_write_char(f, ')'); |
326 |
} |
} |
327 |
} |
} |
358 |
fatal("out of memory"); |
fatal("out of memory"); |
359 |
} |
} |
360 |
} |
} |
361 |
|
bool destructuring = false; |
362 |
for (int i = 0; i < function->nargs; i++) { |
for (int i = 0; i < function->nargs; i++) { |
363 |
if (i > 0) { |
if (i > 0) { |
364 |
Stream_write_string(f, ", "); |
Stream_write_string(f, ", "); |
365 |
} |
} |
366 |
JSAtom * param = JS_LOCAL_NAME_TO_ATOM(local_names[i]); |
JSAtom * param = JS_LOCAL_NAME_TO_ATOM(local_names[i]); |
367 |
if (param == NULL) { |
if (param == NULL) { |
368 |
fatal_source(file_id, node->pn_pos.begin.lineno, "unsupported parameter type for function"); |
destructuring = true; |
369 |
|
JSParseNode * expression = NULL; |
370 |
|
assert(node->pn_body->pn_type == TOK_LC || node->pn_body->pn_type == TOK_BODY); |
371 |
|
JSParseNode * semi = node->pn_body->pn_head; |
372 |
|
assert(semi->pn_type == TOK_SEMI); |
373 |
|
JSParseNode * comma = semi->pn_kid; |
374 |
|
assert(comma->pn_type == TOK_COMMA); |
375 |
|
for (JSParseNode * p = comma->pn_head; p != NULL; p = p->pn_next) { |
376 |
|
assert(p->pn_type == TOK_ASSIGN); |
377 |
|
JSParseNode * rhs = p->pn_right; |
378 |
|
assert(JSSTRING_LENGTH(ATOM_TO_STRING(rhs->pn_atom)) == 0); |
379 |
|
if (rhs->pn_slot == i) { |
380 |
|
expression = p->pn_left; |
381 |
|
break; |
382 |
|
} |
383 |
|
} |
384 |
|
assert(expression != NULL); |
385 |
|
output_expression(expression, f, false); |
386 |
|
} |
387 |
|
else { |
388 |
|
print_string_atom(param, f); |
389 |
} |
} |
|
print_string_atom(param, f); |
|
390 |
} |
} |
391 |
JS_FinishArenaPool(&pool); |
JS_FinishArenaPool(&pool); |
392 |
Stream_write_string(f, ") {\n"); |
Stream_write_string(f, ") {\n"); |
393 |
|
|
394 |
/* function body */ |
/* function body */ |
395 |
if (function->flags & JSFUN_EXPR_CLOSURE) { |
if (function->flags & JSFUN_EXPR_CLOSURE) { |
396 |
/* expression closure */ |
/* expression closure - use output_statement instead of instrument_statement */ |
397 |
output_statement(node->pn_body, f, indent + 2, false); |
if (node->pn_body->pn_type == TOK_BODY) { |
398 |
|
assert(node->pn_body->pn_arity == PN_LIST); |
399 |
|
assert(node->pn_body->pn_count == 2); |
400 |
|
output_statement(node->pn_body->pn_head->pn_next, f, indent + 2, false); |
401 |
|
} |
402 |
|
else { |
403 |
|
output_statement(node->pn_body, f, indent + 2, false); |
404 |
|
} |
405 |
} |
} |
406 |
else { |
else { |
407 |
instrument_statement(node->pn_body, f, indent + 2, false); |
assert(node->pn_body->pn_type == TOK_LC); |
408 |
|
assert(node->pn_body->pn_arity == PN_LIST); |
409 |
|
JSParseNode * p = node->pn_body->pn_head; |
410 |
|
if (destructuring) { |
411 |
|
p = p->pn_next; |
412 |
|
} |
413 |
|
for (; p != NULL; p = p->pn_next) { |
414 |
|
instrument_statement(p, f, indent + 2, false); |
415 |
|
} |
416 |
} |
} |
417 |
|
|
418 |
Stream_write_string(f, "}\n"); |
Stream_write_char(f, '}'); |
419 |
} |
} |
420 |
|
|
421 |
static void instrument_function_call(JSParseNode * node, Stream * f) { |
static void instrument_function_call(JSParseNode * node, Stream * f) { |
434 |
Stream_write_char(f, ')'); |
Stream_write_char(f, ')'); |
435 |
return; |
return; |
436 |
} |
} |
|
else { |
|
|
Stream_write_char(f, '('); |
|
|
instrument_expression(function_node, f); |
|
|
Stream_write_char(f, ')'); |
|
|
} |
|
|
} |
|
|
else { |
|
|
instrument_expression(function_node, f); |
|
437 |
} |
} |
438 |
|
output_expression(function_node, f, false); |
439 |
Stream_write_char(f, '('); |
Stream_write_char(f, '('); |
440 |
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) { |
441 |
if (p != node->pn_head->pn_next) { |
if (p != node->pn_head->pn_next) { |
442 |
Stream_write_string(f, ", "); |
Stream_write_string(f, ", "); |
443 |
} |
} |
444 |
instrument_expression(p, f); |
output_expression(p, f, false); |
445 |
} |
} |
446 |
Stream_write_char(f, ')'); |
Stream_write_char(f, ')'); |
447 |
} |
} |
449 |
static void instrument_declarations(JSParseNode * list, Stream * f) { |
static void instrument_declarations(JSParseNode * list, Stream * f) { |
450 |
assert(list->pn_arity == PN_LIST); |
assert(list->pn_arity == PN_LIST); |
451 |
for (JSParseNode * p = list->pn_head; p != NULL; p = p->pn_next) { |
for (JSParseNode * p = list->pn_head; p != NULL; p = p->pn_next) { |
452 |
switch (p->pn_type) { |
if (p != list->pn_head) { |
453 |
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; |
|
454 |
} |
} |
455 |
|
output_expression(p, f, false); |
456 |
} |
} |
457 |
} |
} |
458 |
|
|
469 |
TOK_INSTANCEOF binary |
TOK_INSTANCEOF binary |
470 |
TOK_IN binary |
TOK_IN binary |
471 |
*/ |
*/ |
472 |
static void instrument_expression(JSParseNode * node, Stream * f) { |
static void output_expression(JSParseNode * node, Stream * f, bool parenthesize_object_literals) { |
473 |
switch (node->pn_type) { |
switch (node->pn_type) { |
474 |
case TOK_FUNCTION: |
case TOK_FUNCTION: |
475 |
|
Stream_write_char(f, '('); |
476 |
instrument_function(node, f, 0, FUNCTION_NORMAL); |
instrument_function(node, f, 0, FUNCTION_NORMAL); |
477 |
|
Stream_write_char(f, ')'); |
478 |
break; |
break; |
479 |
case TOK_COMMA: |
case TOK_COMMA: |
480 |
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) { |
481 |
if (p != node->pn_head) { |
if (p != node->pn_head) { |
482 |
Stream_write_string(f, ", "); |
Stream_write_string(f, ", "); |
483 |
} |
} |
484 |
instrument_expression(p, f); |
output_expression(p, f, parenthesize_object_literals); |
485 |
} |
} |
486 |
break; |
break; |
487 |
case TOK_ASSIGN: |
case TOK_ASSIGN: |
488 |
instrument_expression(node->pn_left, f); |
output_expression(node->pn_left, f, parenthesize_object_literals); |
489 |
Stream_write_char(f, ' '); |
Stream_write_char(f, ' '); |
490 |
switch (node->pn_op) { |
switch (node->pn_op) { |
491 |
case JSOP_ADD: |
case JSOP_ADD: |
506 |
break; |
break; |
507 |
} |
} |
508 |
Stream_write_string(f, "= "); |
Stream_write_string(f, "= "); |
509 |
instrument_expression(node->pn_right, f); |
output_expression(node->pn_right, f, false); |
510 |
break; |
break; |
511 |
case TOK_HOOK: |
case TOK_HOOK: |
512 |
instrument_expression(node->pn_kid1, f); |
output_expression(node->pn_kid1, f, parenthesize_object_literals); |
513 |
Stream_write_string(f, "? "); |
Stream_write_string(f, "? "); |
514 |
instrument_expression(node->pn_kid2, f); |
output_expression(node->pn_kid2, f, false); |
515 |
Stream_write_string(f, ": "); |
Stream_write_string(f, ": "); |
516 |
instrument_expression(node->pn_kid3, f); |
output_expression(node->pn_kid3, f, false); |
517 |
break; |
break; |
518 |
case TOK_OR: |
case TOK_OR: |
519 |
case TOK_AND: |
case TOK_AND: |
529 |
case TOK_DIVOP: |
case TOK_DIVOP: |
530 |
switch (node->pn_arity) { |
switch (node->pn_arity) { |
531 |
case PN_BINARY: |
case PN_BINARY: |
532 |
instrument_expression(node->pn_left, f); |
output_expression(node->pn_left, f, parenthesize_object_literals); |
533 |
Stream_printf(f, " %s ", get_op(node->pn_op)); |
Stream_printf(f, " %s ", get_op(node->pn_op)); |
534 |
instrument_expression(node->pn_right, f); |
output_expression(node->pn_right, f, false); |
535 |
break; |
break; |
536 |
case PN_LIST: |
case PN_LIST: |
537 |
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) { |
538 |
if (p != node->pn_head) { |
if (p == node->pn_head) { |
539 |
|
output_expression(p, f, parenthesize_object_literals); |
540 |
|
} |
541 |
|
else { |
542 |
Stream_printf(f, " %s ", get_op(node->pn_op)); |
Stream_printf(f, " %s ", get_op(node->pn_op)); |
543 |
|
output_expression(p, f, false); |
544 |
} |
} |
|
instrument_expression(p, f); |
|
545 |
} |
} |
546 |
break; |
break; |
547 |
default: |
default: |
551 |
case TOK_UNARYOP: |
case TOK_UNARYOP: |
552 |
switch (node->pn_op) { |
switch (node->pn_op) { |
553 |
case JSOP_NEG: |
case JSOP_NEG: |
554 |
Stream_write_char(f, '-'); |
Stream_write_string(f, "- "); |
555 |
instrument_expression(node->pn_kid, f); |
output_expression(node->pn_kid, f, false); |
556 |
break; |
break; |
557 |
case JSOP_POS: |
case JSOP_POS: |
558 |
Stream_write_char(f, '+'); |
Stream_write_string(f, "+ "); |
559 |
instrument_expression(node->pn_kid, f); |
output_expression(node->pn_kid, f, false); |
560 |
break; |
break; |
561 |
case JSOP_NOT: |
case JSOP_NOT: |
562 |
Stream_write_char(f, '!'); |
Stream_write_string(f, "! "); |
563 |
instrument_expression(node->pn_kid, f); |
output_expression(node->pn_kid, f, false); |
564 |
break; |
break; |
565 |
case JSOP_BITNOT: |
case JSOP_BITNOT: |
566 |
Stream_write_char(f, '~'); |
Stream_write_string(f, "~ "); |
567 |
instrument_expression(node->pn_kid, f); |
output_expression(node->pn_kid, f, false); |
568 |
break; |
break; |
569 |
case JSOP_TYPEOF: |
case JSOP_TYPEOF: |
570 |
Stream_write_string(f, "typeof "); |
Stream_write_string(f, "typeof "); |
571 |
instrument_expression(node->pn_kid, f); |
output_expression(node->pn_kid, f, false); |
572 |
break; |
break; |
573 |
case JSOP_VOID: |
case JSOP_VOID: |
574 |
Stream_write_string(f, "void "); |
Stream_write_string(f, "void "); |
575 |
instrument_expression(node->pn_kid, f); |
output_expression(node->pn_kid, f, false); |
576 |
break; |
break; |
577 |
default: |
default: |
578 |
fatal_source(file_id, node->pn_pos.begin.lineno, "unknown operator (%d)", node->pn_op); |
fatal_source(file_id, node->pn_pos.begin.lineno, "unknown operator (%d)", node->pn_op); |
589 |
case JSOP_INCPROP: |
case JSOP_INCPROP: |
590 |
case JSOP_INCELEM: |
case JSOP_INCELEM: |
591 |
Stream_write_string(f, "++"); |
Stream_write_string(f, "++"); |
592 |
instrument_expression(node->pn_kid, f); |
output_expression(node->pn_kid, f, false); |
593 |
break; |
break; |
594 |
case JSOP_DECNAME: |
case JSOP_DECNAME: |
595 |
case JSOP_DECPROP: |
case JSOP_DECPROP: |
596 |
case JSOP_DECELEM: |
case JSOP_DECELEM: |
597 |
Stream_write_string(f, "--"); |
Stream_write_string(f, "--"); |
598 |
instrument_expression(node->pn_kid, f); |
output_expression(node->pn_kid, f, false); |
599 |
break; |
break; |
600 |
case JSOP_NAMEINC: |
case JSOP_NAMEINC: |
601 |
case JSOP_PROPINC: |
case JSOP_PROPINC: |
602 |
case JSOP_ELEMINC: |
case JSOP_ELEMINC: |
603 |
instrument_expression(node->pn_kid, f); |
output_expression(node->pn_kid, f, parenthesize_object_literals); |
604 |
Stream_write_string(f, "++"); |
Stream_write_string(f, "++"); |
605 |
break; |
break; |
606 |
case JSOP_NAMEDEC: |
case JSOP_NAMEDEC: |
607 |
case JSOP_PROPDEC: |
case JSOP_PROPDEC: |
608 |
case JSOP_ELEMDEC: |
case JSOP_ELEMDEC: |
609 |
instrument_expression(node->pn_kid, f); |
output_expression(node->pn_kid, f, parenthesize_object_literals); |
610 |
Stream_write_string(f, "--"); |
Stream_write_string(f, "--"); |
611 |
break; |
break; |
612 |
default: |
default: |
620 |
break; |
break; |
621 |
case TOK_DELETE: |
case TOK_DELETE: |
622 |
Stream_write_string(f, "delete "); |
Stream_write_string(f, "delete "); |
623 |
instrument_expression(node->pn_kid, f); |
output_expression(node->pn_kid, f, false); |
624 |
break; |
break; |
625 |
case TOK_DOT: |
case TOK_DOT: |
626 |
|
/* numeric literals must be parenthesized */ |
627 |
|
switch (node->pn_expr->pn_type) { |
628 |
|
case TOK_NUMBER: |
629 |
|
Stream_write_char(f, '('); |
630 |
|
output_expression(node->pn_expr, f, false); |
631 |
|
Stream_write_char(f, ')'); |
632 |
|
break; |
633 |
|
default: |
634 |
|
output_expression(node->pn_expr, f, true); |
635 |
|
break; |
636 |
|
} |
637 |
/* |
/* |
638 |
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' |
639 |
contains illegal characters, we have to use the subscript syntax instead of |
contains illegal characters, we have to use the subscript syntax instead of |
640 |
the dot syntax. |
the dot syntax. |
641 |
*/ |
*/ |
|
instrument_expression(node->pn_expr, f); |
|
642 |
assert(ATOM_IS_STRING(node->pn_atom)); |
assert(ATOM_IS_STRING(node->pn_atom)); |
643 |
{ |
{ |
644 |
JSString * s = ATOM_TO_STRING(node->pn_atom); |
JSString * s = ATOM_TO_STRING(node->pn_atom); |
667 |
} |
} |
668 |
break; |
break; |
669 |
case TOK_LB: |
case TOK_LB: |
670 |
instrument_expression(node->pn_left, f); |
output_expression(node->pn_left, f, false); |
671 |
Stream_write_char(f, '['); |
Stream_write_char(f, '['); |
672 |
instrument_expression(node->pn_right, f); |
output_expression(node->pn_right, f, false); |
673 |
Stream_write_char(f, ']'); |
Stream_write_char(f, ']'); |
674 |
break; |
break; |
675 |
case TOK_LP: |
case TOK_LP: |
683 |
} |
} |
684 |
/* TOK_COMMA is a special case: a hole in the array */ |
/* TOK_COMMA is a special case: a hole in the array */ |
685 |
if (p->pn_type != TOK_COMMA) { |
if (p->pn_type != TOK_COMMA) { |
686 |
instrument_expression(p, f); |
output_expression(p, f, false); |
687 |
} |
} |
688 |
} |
} |
689 |
if (node->pn_extra == PNX_ENDCOMMA) { |
if (node->pn_extra == PNX_ENDCOMMA) { |
692 |
Stream_write_char(f, ']'); |
Stream_write_char(f, ']'); |
693 |
break; |
break; |
694 |
case TOK_RC: |
case TOK_RC: |
695 |
|
if (parenthesize_object_literals) { |
696 |
|
Stream_write_char(f, '('); |
697 |
|
} |
698 |
Stream_write_char(f, '{'); |
Stream_write_char(f, '{'); |
699 |
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) { |
700 |
if (p->pn_type != TOK_COLON) { |
if (p->pn_type != TOK_COLON) { |
714 |
else { |
else { |
715 |
Stream_write_string(f, "set "); |
Stream_write_string(f, "set "); |
716 |
} |
} |
717 |
instrument_expression(p->pn_left, f); |
output_expression(p->pn_left, f, false); |
718 |
|
Stream_write_char(f, ' '); |
719 |
if (p->pn_right->pn_type != TOK_FUNCTION) { |
if (p->pn_right->pn_type != TOK_FUNCTION) { |
720 |
fatal_source(file_id, p->pn_pos.begin.lineno, "expected function"); |
fatal_source(file_id, p->pn_pos.begin.lineno, "expected function"); |
721 |
} |
} |
722 |
instrument_function(p->pn_right, f, 0, FUNCTION_GETTER_OR_SETTER); |
instrument_function(p->pn_right, f, 0, FUNCTION_GETTER_OR_SETTER); |
723 |
break; |
break; |
724 |
default: |
default: |
725 |
instrument_expression(p->pn_left, f); |
output_expression(p->pn_left, f, false); |
726 |
Stream_write_string(f, ": "); |
Stream_write_string(f, ": "); |
727 |
instrument_expression(p->pn_right, f); |
output_expression(p->pn_right, f, false); |
728 |
break; |
break; |
729 |
} |
} |
730 |
} |
} |
731 |
Stream_write_char(f, '}'); |
Stream_write_char(f, '}'); |
732 |
|
if (parenthesize_object_literals) { |
733 |
|
Stream_write_char(f, ')'); |
734 |
|
} |
735 |
break; |
break; |
736 |
case TOK_RP: |
case TOK_RP: |
737 |
Stream_write_char(f, '('); |
Stream_write_char(f, '('); |
738 |
instrument_expression(node->pn_kid, f); |
output_expression(node->pn_kid, f, false); |
739 |
Stream_write_char(f, ')'); |
Stream_write_char(f, ')'); |
740 |
break; |
break; |
741 |
case TOK_NAME: |
case TOK_NAME: |
742 |
print_string_atom(node->pn_atom, f); |
print_string_atom(node->pn_atom, f); |
743 |
|
if (node->pn_expr != NULL) { |
744 |
|
Stream_write_string(f, " = "); |
745 |
|
output_expression(node->pn_expr, f, false); |
746 |
|
} |
747 |
break; |
break; |
748 |
case TOK_STRING: |
case TOK_STRING: |
749 |
print_quoted_string_atom(node->pn_atom, f); |
print_quoted_string_atom(node->pn_atom, f); |
765 |
To keep the output simple, special-case zero. |
To keep the output simple, special-case zero. |
766 |
*/ |
*/ |
767 |
if (node->pn_dval == 0.0) { |
if (node->pn_dval == 0.0) { |
768 |
Stream_write_string(f, "0"); |
if (signbit(node->pn_dval)) { |
769 |
|
Stream_write_string(f, "-0"); |
770 |
|
} |
771 |
|
else { |
772 |
|
Stream_write_string(f, "0"); |
773 |
|
} |
774 |
|
} |
775 |
|
else if (node->pn_dval == INFINITY) { |
776 |
|
Stream_write_string(f, "Number.POSITIVE_INFINITY"); |
777 |
|
} |
778 |
|
else if (node->pn_dval == -INFINITY) { |
779 |
|
Stream_write_string(f, "Number.NEGATIVE_INFINITY"); |
780 |
|
} |
781 |
|
else if (isnan(node->pn_dval)) { |
782 |
|
Stream_write_string(f, "Number.NaN"); |
783 |
} |
} |
784 |
else { |
else { |
785 |
Stream_printf(f, "%.15g", node->pn_dval); |
Stream_printf(f, "%.15g", node->pn_dval); |
805 |
} |
} |
806 |
break; |
break; |
807 |
case TOK_INSTANCEOF: |
case TOK_INSTANCEOF: |
808 |
instrument_expression(node->pn_left, f); |
output_expression(node->pn_left, f, parenthesize_object_literals); |
809 |
Stream_write_string(f, " instanceof "); |
Stream_write_string(f, " instanceof "); |
810 |
instrument_expression(node->pn_right, f); |
output_expression(node->pn_right, f, false); |
811 |
break; |
break; |
812 |
case TOK_IN: |
case TOK_IN: |
813 |
instrument_expression(node->pn_left, f); |
output_expression(node->pn_left, f, false); |
814 |
Stream_write_string(f, " in "); |
Stream_write_string(f, " in "); |
815 |
instrument_expression(node->pn_right, f); |
output_expression(node->pn_right, f, false); |
816 |
break; |
break; |
817 |
case TOK_LEXICALSCOPE: |
case TOK_LEXICALSCOPE: |
818 |
assert(node->pn_arity == PN_NAME); |
assert(node->pn_arity == PN_NAME); |
823 |
assert(node->pn_expr->pn_left->pn_arity == PN_LIST); |
assert(node->pn_expr->pn_left->pn_arity == PN_LIST); |
824 |
instrument_declarations(node->pn_expr->pn_left, f); |
instrument_declarations(node->pn_expr->pn_left, f); |
825 |
Stream_write_string(f, ") "); |
Stream_write_string(f, ") "); |
826 |
instrument_expression(node->pn_expr->pn_right, f); |
output_expression(node->pn_expr->pn_right, f, true); |
827 |
break; |
break; |
828 |
case TOK_YIELD: |
case TOK_YIELD: |
829 |
assert(node->pn_arity == PN_UNARY); |
assert(node->pn_arity == PN_UNARY); |
830 |
Stream_write_string(f, "yield"); |
Stream_write_string(f, "yield"); |
831 |
if (node->pn_kid != NULL) { |
if (node->pn_kid != NULL) { |
832 |
Stream_write_char(f, ' '); |
Stream_write_char(f, ' '); |
833 |
instrument_expression(node->pn_kid, f); |
output_expression(node->pn_kid, f, true); |
834 |
} |
} |
835 |
break; |
break; |
836 |
case TOK_ARRAYCOMP: |
case TOK_ARRAYCOMP: |
872 |
switch (node->pn_type) { |
switch (node->pn_type) { |
873 |
case TOK_FUNCTION: |
case TOK_FUNCTION: |
874 |
instrument_function(node, f, indent, FUNCTION_NORMAL); |
instrument_function(node, f, indent, FUNCTION_NORMAL); |
875 |
|
Stream_write_char(f, '\n'); |
876 |
break; |
break; |
877 |
case TOK_LC: |
case TOK_LC: |
878 |
assert(node->pn_arity == PN_LIST); |
assert(node->pn_arity == PN_LIST); |
903 |
|
|
904 |
Stream_printf(f, "%*s", indent, ""); |
Stream_printf(f, "%*s", indent, ""); |
905 |
Stream_write_string(f, "if ("); |
Stream_write_string(f, "if ("); |
906 |
instrument_expression(node->pn_kid1, f); |
output_expression(node->pn_kid1, f, false); |
907 |
Stream_write_string(f, ") {\n"); |
Stream_write_string(f, ") {\n"); |
908 |
if (is_jscoverage_if && node->pn_kid3) { |
if (is_jscoverage_if && node->pn_kid3) { |
909 |
uint16_t else_start = node->pn_kid3->pn_pos.begin.lineno; |
uint16_t else_start = node->pn_kid3->pn_pos.begin.lineno; |
940 |
assert(node->pn_arity == PN_BINARY); |
assert(node->pn_arity == PN_BINARY); |
941 |
Stream_printf(f, "%*s", indent, ""); |
Stream_printf(f, "%*s", indent, ""); |
942 |
Stream_write_string(f, "switch ("); |
Stream_write_string(f, "switch ("); |
943 |
instrument_expression(node->pn_left, f); |
output_expression(node->pn_left, f, false); |
944 |
Stream_write_string(f, ") {\n"); |
Stream_write_string(f, ") {\n"); |
945 |
{ |
{ |
946 |
JSParseNode * list = node->pn_right; |
JSParseNode * list = node->pn_right; |
952 |
switch (p->pn_type) { |
switch (p->pn_type) { |
953 |
case TOK_CASE: |
case TOK_CASE: |
954 |
Stream_write_string(f, "case "); |
Stream_write_string(f, "case "); |
955 |
instrument_expression(p->pn_left, f); |
output_expression(p->pn_left, f, false); |
956 |
Stream_write_string(f, ":\n"); |
Stream_write_string(f, ":\n"); |
957 |
break; |
break; |
958 |
case TOK_DEFAULT: |
case TOK_DEFAULT: |
976 |
assert(node->pn_arity == PN_BINARY); |
assert(node->pn_arity == PN_BINARY); |
977 |
Stream_printf(f, "%*s", indent, ""); |
Stream_printf(f, "%*s", indent, ""); |
978 |
Stream_write_string(f, "while ("); |
Stream_write_string(f, "while ("); |
979 |
instrument_expression(node->pn_left, f); |
output_expression(node->pn_left, f, false); |
980 |
Stream_write_string(f, ") {\n"); |
Stream_write_string(f, ") {\n"); |
981 |
instrument_statement(node->pn_right, f, indent + 2, false); |
instrument_statement(node->pn_right, f, indent + 2, false); |
982 |
Stream_write_string(f, "}\n"); |
Stream_write_string(f, "}\n"); |
989 |
Stream_write_string(f, "}\n"); |
Stream_write_string(f, "}\n"); |
990 |
Stream_printf(f, "%*s", indent, ""); |
Stream_printf(f, "%*s", indent, ""); |
991 |
Stream_write_string(f, "while ("); |
Stream_write_string(f, "while ("); |
992 |
instrument_expression(node->pn_right, f); |
output_expression(node->pn_right, f, false); |
993 |
Stream_write_string(f, ");\n"); |
Stream_write_string(f, ");\n"); |
994 |
break; |
break; |
995 |
case TOK_FOR: |
case TOK_FOR: |
1006 |
assert(node->pn_left->pn_arity == PN_TERNARY); |
assert(node->pn_left->pn_arity == PN_TERNARY); |
1007 |
Stream_write_string(f, "for ("); |
Stream_write_string(f, "for ("); |
1008 |
if (node->pn_left->pn_kid1) { |
if (node->pn_left->pn_kid1) { |
1009 |
instrument_expression(node->pn_left->pn_kid1, f); |
output_expression(node->pn_left->pn_kid1, f, false); |
1010 |
} |
} |
1011 |
Stream_write_string(f, ";"); |
Stream_write_string(f, ";"); |
1012 |
if (node->pn_left->pn_kid2) { |
if (node->pn_left->pn_kid2) { |
1013 |
Stream_write_char(f, ' '); |
Stream_write_char(f, ' '); |
1014 |
instrument_expression(node->pn_left->pn_kid2, f); |
output_expression(node->pn_left->pn_kid2, f, false); |
1015 |
} |
} |
1016 |
Stream_write_string(f, ";"); |
Stream_write_string(f, ";"); |
1017 |
if (node->pn_left->pn_kid3) { |
if (node->pn_left->pn_kid3) { |
1018 |
Stream_write_char(f, ' '); |
Stream_write_char(f, ' '); |
1019 |
instrument_expression(node->pn_left->pn_kid3, f); |
output_expression(node->pn_left->pn_kid3, f, false); |
1020 |
} |
} |
1021 |
Stream_write_char(f, ')'); |
Stream_write_char(f, ')'); |
1022 |
break; |
break; |
1032 |
assert(node->pn_arity == PN_UNARY); |
assert(node->pn_arity == PN_UNARY); |
1033 |
Stream_printf(f, "%*s", indent, ""); |
Stream_printf(f, "%*s", indent, ""); |
1034 |
Stream_write_string(f, "throw "); |
Stream_write_string(f, "throw "); |
1035 |
instrument_expression(node->pn_u.unary.kid, f); |
output_expression(node->pn_u.unary.kid, f, false); |
1036 |
Stream_write_string(f, ";\n"); |
Stream_write_string(f, ";\n"); |
1037 |
break; |
break; |
1038 |
case TOK_TRY: |
case TOK_TRY: |
1049 |
assert(catch->pn_type == TOK_CATCH); |
assert(catch->pn_type == TOK_CATCH); |
1050 |
Stream_printf(f, "%*s", indent, ""); |
Stream_printf(f, "%*s", indent, ""); |
1051 |
Stream_write_string(f, "catch ("); |
Stream_write_string(f, "catch ("); |
1052 |
/* 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); |
|
1053 |
if (catch->pn_kid2) { |
if (catch->pn_kid2) { |
1054 |
Stream_write_string(f, " if "); |
Stream_write_string(f, " if "); |
1055 |
instrument_expression(catch->pn_kid2, f); |
output_expression(catch->pn_kid2, f, false); |
1056 |
} |
} |
1057 |
Stream_write_string(f, ") {\n"); |
Stream_write_string(f, ") {\n"); |
1058 |
instrument_statement(catch->pn_kid3, f, indent + 2, false); |
instrument_statement(catch->pn_kid3, f, indent + 2, false); |
1087 |
assert(node->pn_arity == PN_BINARY); |
assert(node->pn_arity == PN_BINARY); |
1088 |
Stream_printf(f, "%*s", indent, ""); |
Stream_printf(f, "%*s", indent, ""); |
1089 |
Stream_write_string(f, "with ("); |
Stream_write_string(f, "with ("); |
1090 |
instrument_expression(node->pn_left, f); |
output_expression(node->pn_left, f, false); |
1091 |
Stream_write_string(f, ") {\n"); |
Stream_write_string(f, ") {\n"); |
1092 |
instrument_statement(node->pn_right, f, indent + 2, false); |
instrument_statement(node->pn_right, f, indent + 2, false); |
1093 |
Stream_printf(f, "%*s", indent, ""); |
Stream_printf(f, "%*s", indent, ""); |
1095 |
break; |
break; |
1096 |
case TOK_VAR: |
case TOK_VAR: |
1097 |
Stream_printf(f, "%*s", indent, ""); |
Stream_printf(f, "%*s", indent, ""); |
1098 |
instrument_expression(node, f); |
output_expression(node, f, false); |
1099 |
Stream_write_string(f, ";\n"); |
Stream_write_string(f, ";\n"); |
1100 |
break; |
break; |
1101 |
case TOK_RETURN: |
case TOK_RETURN: |
1104 |
Stream_write_string(f, "return"); |
Stream_write_string(f, "return"); |
1105 |
if (node->pn_kid != NULL) { |
if (node->pn_kid != NULL) { |
1106 |
Stream_write_char(f, ' '); |
Stream_write_char(f, ' '); |
1107 |
instrument_expression(node->pn_kid, f); |
output_expression(node->pn_kid, f, true); |
1108 |
} |
} |
1109 |
Stream_write_string(f, ";\n"); |
Stream_write_string(f, ";\n"); |
1110 |
break; |
break; |
1112 |
assert(node->pn_arity == PN_UNARY); |
assert(node->pn_arity == PN_UNARY); |
1113 |
Stream_printf(f, "%*s", indent, ""); |
Stream_printf(f, "%*s", indent, ""); |
1114 |
if (node->pn_kid != NULL) { |
if (node->pn_kid != NULL) { |
1115 |
instrument_expression(node->pn_kid, f); |
output_expression(node->pn_kid, f, true); |
1116 |
} |
} |
1117 |
Stream_write_string(f, ";\n"); |
Stream_write_string(f, ";\n"); |
1118 |
break; |
break; |
1119 |
case TOK_COLON: |
case TOK_COLON: |
1120 |
|
{ |
1121 |
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 ... |
|
|
*/ |
|
1122 |
Stream_printf(f, "%*s", indent < 2? 0: indent - 2, ""); |
Stream_printf(f, "%*s", indent < 2? 0: indent - 2, ""); |
1123 |
print_string_atom(node->pn_atom, f); |
print_string_atom(node->pn_atom, f); |
1124 |
Stream_write_string(f, ":\n"); |
Stream_write_string(f, ":\n"); |
1125 |
/* |
JSParseNode * labelled = node->pn_expr; |
1126 |
... use output_statement instead of instrument_statement. |
if (labelled->pn_type == TOK_LEXICALSCOPE) { |
1127 |
*/ |
labelled = labelled->pn_expr; |
1128 |
output_statement(node->pn_expr, f, indent, false); |
} |
1129 |
|
if (labelled->pn_type == TOK_LC) { |
1130 |
|
/* labelled block */ |
1131 |
|
Stream_printf(f, "%*s", indent, ""); |
1132 |
|
Stream_write_string(f, "{\n"); |
1133 |
|
instrument_statement(labelled, f, indent + 2, false); |
1134 |
|
Stream_printf(f, "%*s", indent, ""); |
1135 |
|
Stream_write_string(f, "}\n"); |
1136 |
|
} |
1137 |
|
else { |
1138 |
|
/* |
1139 |
|
This one is tricky: can't output instrumentation between the label and the |
1140 |
|
statement it's supposed to label, so use output_statement instead of |
1141 |
|
instrument_statement. |
1142 |
|
*/ |
1143 |
|
output_statement(labelled, f, indent, false); |
1144 |
|
} |
1145 |
break; |
break; |
1146 |
|
} |
1147 |
case TOK_LEXICALSCOPE: |
case TOK_LEXICALSCOPE: |
1148 |
/* let statement */ |
/* let statement */ |
1149 |
assert(node->pn_arity == PN_NAME); |
assert(node->pn_arity == PN_NAME); |
1186 |
case PN_LIST: |
case PN_LIST: |
1187 |
/* let definition */ |
/* let definition */ |
1188 |
Stream_printf(f, "%*s", indent, ""); |
Stream_printf(f, "%*s", indent, ""); |
1189 |
instrument_expression(node, f); |
output_expression(node, f, false); |
1190 |
Stream_write_string(f, ";\n"); |
Stream_write_string(f, ";\n"); |
1191 |
break; |
break; |
1192 |
default: |
default: |