257 |
|
|
258 |
static void instrument_expression(JSParseNode * node, Stream * f); |
static void instrument_expression(JSParseNode * node, Stream * f); |
259 |
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); |
260 |
|
static void output_statement(JSParseNode * node, Stream * f, int indent, bool is_jscoverage_if); |
261 |
|
|
262 |
enum FunctionType { |
enum FunctionType { |
263 |
FUNCTION_NORMAL, |
FUNCTION_NORMAL, |
308 |
Stream_write_string(f, ") {\n"); |
Stream_write_string(f, ") {\n"); |
309 |
|
|
310 |
/* function body */ |
/* function body */ |
311 |
instrument_statement(node->pn_body, f, indent + 2, false); |
if (function->flags & JSFUN_EXPR_CLOSURE) { |
312 |
|
/* expression closure */ |
313 |
|
output_statement(node->pn_body, f, indent + 2, false); |
314 |
|
} |
315 |
|
else { |
316 |
|
instrument_statement(node->pn_body, f, indent + 2, false); |
317 |
|
} |
318 |
|
|
319 |
Stream_write_string(f, "}\n"); |
Stream_write_string(f, "}\n"); |
320 |
} |
} |
359 |
} |
} |
360 |
} |
} |
361 |
|
|
362 |
|
static void output_for_in(JSParseNode * node, Stream * f) { |
363 |
|
assert(node->pn_type == TOK_FOR); |
364 |
|
assert(node->pn_arity == PN_BINARY); |
365 |
|
Stream_write_string(f, "for "); |
366 |
|
if (node->pn_iflags & JSITER_FOREACH) { |
367 |
|
Stream_write_string(f, "each "); |
368 |
|
} |
369 |
|
Stream_write_char(f, '('); |
370 |
|
instrument_expression(node->pn_left, f); |
371 |
|
Stream_write_char(f, ')'); |
372 |
|
} |
373 |
|
|
374 |
/* |
/* |
375 |
See <Expressions> in jsparse.h. |
See <Expressions> in jsparse.h. |
376 |
TOK_FUNCTION is handled as a statement and as an expression. |
TOK_FUNCTION is handled as a statement and as an expression. |
686 |
Stream_write_string(f, ") "); |
Stream_write_string(f, ") "); |
687 |
instrument_expression(node->pn_expr->pn_right, f); |
instrument_expression(node->pn_expr->pn_right, f); |
688 |
break; |
break; |
689 |
|
case TOK_YIELD: |
690 |
|
assert(node->pn_arity == PN_UNARY); |
691 |
|
Stream_write_string(f, "yield "); |
692 |
|
instrument_expression(node->pn_kid, f); |
693 |
|
break; |
694 |
|
case TOK_ARRAYCOMP: |
695 |
|
assert(node->pn_arity == PN_LIST); |
696 |
|
{ |
697 |
|
JSParseNode * block_node; |
698 |
|
switch (node->pn_count) { |
699 |
|
case 1: |
700 |
|
block_node = node->pn_head; |
701 |
|
break; |
702 |
|
case 2: |
703 |
|
block_node = node->pn_head->pn_next; |
704 |
|
break; |
705 |
|
default: |
706 |
|
abort(); |
707 |
|
break; |
708 |
|
} |
709 |
|
assert(block_node->pn_type == TOK_LEXICALSCOPE); |
710 |
|
assert(block_node->pn_arity == PN_NAME); |
711 |
|
JSParseNode * for_node = block_node->pn_expr; |
712 |
|
assert(for_node->pn_type == TOK_FOR); |
713 |
|
assert(for_node->pn_arity == PN_BINARY); |
714 |
|
JSParseNode * push_node; |
715 |
|
JSParseNode * if_node = NULL; |
716 |
|
switch (for_node->pn_right->pn_type) { |
717 |
|
case TOK_ARRAYPUSH: |
718 |
|
push_node = for_node->pn_right; |
719 |
|
assert(push_node->pn_arity == PN_UNARY); |
720 |
|
break; |
721 |
|
case TOK_IF: |
722 |
|
if_node = for_node->pn_right; |
723 |
|
assert(if_node->pn_arity == PN_TERNARY); |
724 |
|
push_node = if_node->pn_kid2; |
725 |
|
break; |
726 |
|
default: |
727 |
|
abort(); |
728 |
|
break; |
729 |
|
} |
730 |
|
Stream_write_char(f, '['); |
731 |
|
instrument_expression(push_node->pn_kid, f); |
732 |
|
Stream_write_char(f, ' '); |
733 |
|
output_for_in(for_node, f); |
734 |
|
if (if_node) { |
735 |
|
Stream_write_string(f, " if ("); |
736 |
|
instrument_expression(if_node->pn_kid1, f); |
737 |
|
Stream_write_char(f, ')'); |
738 |
|
} |
739 |
|
Stream_write_char(f, ']'); |
740 |
|
} |
741 |
|
break; |
742 |
|
case TOK_VAR: |
743 |
|
assert(node->pn_arity == PN_LIST); |
744 |
|
Stream_write_string(f, "var "); |
745 |
|
instrument_declarations(node, f); |
746 |
|
break; |
747 |
|
case TOK_LET: |
748 |
|
assert(node->pn_arity == PN_LIST); |
749 |
|
Stream_write_string(f, "let "); |
750 |
|
instrument_declarations(node, f); |
751 |
|
break; |
752 |
default: |
default: |
753 |
fatal("unsupported node type in file %s: %d", file_id, node->pn_type); |
fatal("unsupported node type in file %s: %d", file_id, node->pn_type); |
754 |
} |
} |
755 |
} |
} |
756 |
|
|
|
static void instrument_var_statement(JSParseNode * node, Stream * f, int indent) { |
|
|
assert(node->pn_arity == PN_LIST); |
|
|
Stream_printf(f, "%*s", indent, ""); |
|
|
Stream_write_string(f, "var "); |
|
|
instrument_declarations(node, f); |
|
|
} |
|
|
|
|
|
static void instrument_let_definition(JSParseNode * node, Stream * f, int indent) { |
|
|
assert(node->pn_arity == PN_LIST); |
|
|
Stream_printf(f, "%*s", indent, ""); |
|
|
Stream_write_string(f, "let "); |
|
|
instrument_declarations(node, f); |
|
|
} |
|
|
|
|
757 |
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) { |
758 |
switch (node->pn_type) { |
switch (node->pn_type) { |
759 |
case TOK_FUNCTION: |
case TOK_FUNCTION: |
874 |
case TOK_FOR: |
case TOK_FOR: |
875 |
assert(node->pn_arity == PN_BINARY); |
assert(node->pn_arity == PN_BINARY); |
876 |
Stream_printf(f, "%*s", indent, ""); |
Stream_printf(f, "%*s", indent, ""); |
|
Stream_write_string(f, "for "); |
|
|
if (node->pn_iflags & JSITER_FOREACH) { |
|
|
Stream_write_string(f, "each "); |
|
|
} |
|
|
Stream_write_char(f, '('); |
|
877 |
switch (node->pn_left->pn_type) { |
switch (node->pn_left->pn_type) { |
878 |
case TOK_IN: |
case TOK_IN: |
879 |
/* for/in */ |
/* for/in */ |
880 |
assert(node->pn_left->pn_arity == PN_BINARY); |
assert(node->pn_left->pn_arity == PN_BINARY); |
881 |
switch (node->pn_left->pn_left->pn_type) { |
output_for_in(node, f); |
|
case TOK_VAR: |
|
|
instrument_var_statement(node->pn_left->pn_left, f, 0); |
|
|
break; |
|
|
case TOK_LET: |
|
|
instrument_let_definition(node->pn_left->pn_left, f, 0); |
|
|
break; |
|
|
case TOK_NAME: |
|
|
instrument_expression(node->pn_left->pn_left, f); |
|
|
break; |
|
|
default: |
|
|
/* this is undocumented: for (x.value in y) */ |
|
|
instrument_expression(node->pn_left->pn_left, f); |
|
|
break; |
|
|
/* |
|
|
default: |
|
|
fprintf(stderr, "unexpected node type: %d\n", node->pn_left->pn_left->pn_type); |
|
|
abort(); |
|
|
break; |
|
|
*/ |
|
|
} |
|
|
Stream_write_string(f, " in "); |
|
|
instrument_expression(node->pn_left->pn_right, f); |
|
882 |
break; |
break; |
883 |
case TOK_RESERVED: |
case TOK_RESERVED: |
884 |
/* for (;;) */ |
/* for (;;) */ |
885 |
assert(node->pn_left->pn_arity == PN_TERNARY); |
assert(node->pn_left->pn_arity == PN_TERNARY); |
886 |
|
Stream_write_string(f, "for ("); |
887 |
if (node->pn_left->pn_kid1) { |
if (node->pn_left->pn_kid1) { |
888 |
switch (node->pn_left->pn_kid1->pn_type) { |
instrument_expression(node->pn_left->pn_kid1, f); |
|
case TOK_VAR: |
|
|
instrument_var_statement(node->pn_left->pn_kid1, f, 0); |
|
|
break; |
|
|
case TOK_LET: |
|
|
instrument_let_definition(node->pn_left->pn_kid1, f, 0); |
|
|
break; |
|
|
default: |
|
|
instrument_expression(node->pn_left->pn_kid1, f); |
|
|
break; |
|
|
} |
|
889 |
} |
} |
890 |
Stream_write_string(f, ";"); |
Stream_write_string(f, ";"); |
891 |
if (node->pn_left->pn_kid2) { |
if (node->pn_left->pn_kid2) { |
897 |
Stream_write_char(f, ' '); |
Stream_write_char(f, ' '); |
898 |
instrument_expression(node->pn_left->pn_kid3, f); |
instrument_expression(node->pn_left->pn_kid3, f); |
899 |
} |
} |
900 |
|
Stream_write_char(f, ')'); |
901 |
break; |
break; |
902 |
default: |
default: |
903 |
abort(); |
abort(); |
904 |
break; |
break; |
905 |
} |
} |
906 |
Stream_write_string(f, ") {\n"); |
Stream_write_string(f, " {\n"); |
907 |
instrument_statement(node->pn_right, f, indent + 2, false); |
instrument_statement(node->pn_right, f, indent + 2, false); |
908 |
Stream_write_string(f, "}\n"); |
Stream_write_string(f, "}\n"); |
909 |
break; |
break; |
978 |
Stream_write_string(f, "}\n"); |
Stream_write_string(f, "}\n"); |
979 |
break; |
break; |
980 |
case TOK_VAR: |
case TOK_VAR: |
981 |
instrument_var_statement(node, f, indent); |
Stream_printf(f, "%*s", indent, ""); |
982 |
|
instrument_expression(node, f); |
983 |
Stream_write_string(f, ";\n"); |
Stream_write_string(f, ";\n"); |
984 |
break; |
break; |
985 |
case TOK_RETURN: |
case TOK_RETURN: |
1055 |
break; |
break; |
1056 |
case PN_LIST: |
case PN_LIST: |
1057 |
/* let definition */ |
/* let definition */ |
1058 |
instrument_let_definition(node, f, indent); |
Stream_printf(f, "%*s", indent, ""); |
1059 |
|
instrument_expression(node, f); |
1060 |
Stream_write_string(f, ";\n"); |
Stream_write_string(f, ";\n"); |
1061 |
break; |
break; |
1062 |
default: |
default: |