28 |
#include <jsapi.h> |
#include <jsapi.h> |
29 |
#include <jsarena.h> |
#include <jsarena.h> |
30 |
#include <jsatom.h> |
#include <jsatom.h> |
31 |
|
#include <jsemit.h> |
32 |
#include <jsexn.h> |
#include <jsexn.h> |
33 |
#include <jsfun.h> |
#include <jsfun.h> |
34 |
#include <jsinterp.h> |
#include <jsinterp.h> |
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) { |
269 |
|
|
270 |
static void instrument_expression(JSParseNode * node, Stream * f); |
static void instrument_expression(JSParseNode * node, Stream * f); |
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); |
273 |
|
|
274 |
enum FunctionType { |
enum FunctionType { |
275 |
FUNCTION_NORMAL, |
FUNCTION_NORMAL, |
276 |
FUNCTION_GETTER_OR_SETTER |
FUNCTION_GETTER_OR_SETTER |
277 |
}; |
}; |
278 |
|
|
279 |
|
static void output_for_in(JSParseNode * node, Stream * f) { |
280 |
|
assert(node->pn_type == TOK_FOR); |
281 |
|
assert(node->pn_arity == PN_BINARY); |
282 |
|
Stream_write_string(f, "for "); |
283 |
|
if (node->pn_iflags & JSITER_FOREACH) { |
284 |
|
Stream_write_string(f, "each "); |
285 |
|
} |
286 |
|
Stream_write_char(f, '('); |
287 |
|
instrument_expression(node->pn_left, f); |
288 |
|
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 |
|
instrument_expression(p, f); |
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 |
|
instrument_expression(if_node->pn_kid1, f); |
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 |
print_string_atom(param, f); |
if (param == NULL) { |
367 |
|
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 |
|
instrument_expression(expression, f); |
385 |
|
} |
386 |
|
else { |
387 |
|
print_string_atom(param, f); |
388 |
|
} |
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 |
instrument_statement(node->pn_body, f, indent + 2, false); |
if (function->flags & JSFUN_EXPR_CLOSURE) { |
395 |
|
/* expression closure - use output_statement instead of instrument_statement */ |
396 |
|
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 { |
406 |
|
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_string(f, "}\n"); |
418 |
} |
} |
419 |
|
|
420 |
static void instrument_function_call(JSParseNode * node, Stream * f) { |
static void instrument_function_call(JSParseNode * node, Stream * f) { |
421 |
instrument_expression(node->pn_head, f); |
JSParseNode * function_node = node->pn_head; |
422 |
|
if (function_node->pn_type == TOK_FUNCTION) { |
423 |
|
JSObject * object = function_node->pn_funpob->object; |
424 |
|
assert(JS_ObjectIsFunction(context, object)); |
425 |
|
JSFunction * function = (JSFunction *) JS_GetPrivate(context, object); |
426 |
|
assert(function); |
427 |
|
assert(object == &function->object); |
428 |
|
|
429 |
|
if (function_node->pn_flags & TCF_GENEXP_LAMBDA) { |
430 |
|
/* it's a generator expression */ |
431 |
|
Stream_write_char(f, '('); |
432 |
|
output_array_comprehension_or_generator_expression(function_node->pn_body, f); |
433 |
|
Stream_write_char(f, ')'); |
434 |
|
return; |
435 |
|
} |
436 |
|
else { |
437 |
|
Stream_write_char(f, '('); |
438 |
|
instrument_expression(function_node, f); |
439 |
|
Stream_write_char(f, ')'); |
440 |
|
} |
441 |
|
} |
442 |
|
else { |
443 |
|
instrument_expression(function_node, f); |
444 |
|
} |
445 |
Stream_write_char(f, '('); |
Stream_write_char(f, '('); |
446 |
for (struct JSParseNode * p = node->pn_head->pn_next; p != NULL; p = p->pn_next) { |
for (struct JSParseNode * p = function_node->pn_next; p != NULL; p = p->pn_next) { |
447 |
if (p != node->pn_head->pn_next) { |
if (p != node->pn_head->pn_next) { |
448 |
Stream_write_string(f, ", "); |
Stream_write_string(f, ", "); |
449 |
} |
} |
480 |
} |
} |
481 |
} |
} |
482 |
|
|
|
static void output_for_in(JSParseNode * node, Stream * f) { |
|
|
assert(node->pn_type == TOK_FOR); |
|
|
assert(node->pn_arity == PN_BINARY); |
|
|
Stream_write_string(f, "for "); |
|
|
if (node->pn_iflags & JSITER_FOREACH) { |
|
|
Stream_write_string(f, "each "); |
|
|
} |
|
|
Stream_write_char(f, '('); |
|
|
instrument_expression(node->pn_left, f); |
|
|
Stream_write_char(f, ')'); |
|
|
} |
|
|
|
|
483 |
/* |
/* |
484 |
See <Expressions> in jsparse.h. |
See <Expressions> in jsparse.h. |
485 |
TOK_FUNCTION is handled as a statement and as an expression. |
TOK_FUNCTION is handled as a statement and as an expression. |
594 |
instrument_expression(node->pn_kid, f); |
instrument_expression(node->pn_kid, f); |
595 |
break; |
break; |
596 |
default: |
default: |
597 |
abort(); |
fatal_source(file_id, node->pn_pos.begin.lineno, "unknown operator (%d)", node->pn_op); |
598 |
break; |
break; |
599 |
} |
} |
600 |
break; |
break; |
651 |
assert(ATOM_IS_STRING(node->pn_atom)); |
assert(ATOM_IS_STRING(node->pn_atom)); |
652 |
{ |
{ |
653 |
JSString * s = ATOM_TO_STRING(node->pn_atom); |
JSString * s = ATOM_TO_STRING(node->pn_atom); |
654 |
bool is_keyword = (js_CheckKeyword(JSSTRING_CHARS(s), JSSTRING_LENGTH(s)) != TOK_EOF); |
bool must_quote; |
655 |
if (! is_keyword && js_IsIdentifier(s)) { |
if (JSSTRING_LENGTH(s) == 0) { |
656 |
Stream_write_char(f, '.'); |
must_quote = true; |
657 |
print_string_atom(node->pn_atom, f); |
} |
658 |
|
else if (js_CheckKeyword(JSSTRING_CHARS(s), JSSTRING_LENGTH(s)) != TOK_EOF) { |
659 |
|
must_quote = true; |
660 |
|
} |
661 |
|
else if (! js_IsIdentifier(s)) { |
662 |
|
must_quote = true; |
663 |
} |
} |
664 |
else { |
else { |
665 |
|
must_quote = false; |
666 |
|
} |
667 |
|
if (must_quote) { |
668 |
Stream_write_char(f, '['); |
Stream_write_char(f, '['); |
669 |
print_quoted_string_atom(node->pn_atom, f); |
print_quoted_string_atom(node->pn_atom, f); |
670 |
Stream_write_char(f, ']'); |
Stream_write_char(f, ']'); |
671 |
} |
} |
672 |
|
else { |
673 |
|
Stream_write_char(f, '.'); |
674 |
|
print_string_atom(node->pn_atom, f); |
675 |
|
} |
676 |
} |
} |
677 |
break; |
break; |
678 |
case TOK_LB: |
case TOK_LB: |
703 |
case TOK_RC: |
case TOK_RC: |
704 |
Stream_write_char(f, '{'); |
Stream_write_char(f, '{'); |
705 |
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) { |
706 |
assert(p->pn_type == TOK_COLON); |
if (p->pn_type != TOK_COLON) { |
707 |
|
fatal_source(file_id, p->pn_pos.begin.lineno, "unsupported node type (%d)", p->pn_type); |
708 |
|
} |
709 |
if (p != node->pn_head) { |
if (p != node->pn_head) { |
710 |
Stream_write_string(f, ", "); |
Stream_write_string(f, ", "); |
711 |
} |
} |
722 |
} |
} |
723 |
instrument_expression(p->pn_left, f); |
instrument_expression(p->pn_left, f); |
724 |
if (p->pn_right->pn_type != TOK_FUNCTION) { |
if (p->pn_right->pn_type != TOK_FUNCTION) { |
725 |
fatal("parse error: expected function"); |
fatal_source(file_id, p->pn_pos.begin.lineno, "expected function"); |
726 |
} |
} |
727 |
instrument_function(p->pn_right, f, 0, FUNCTION_GETTER_OR_SETTER); |
instrument_function(p->pn_right, f, 0, FUNCTION_GETTER_OR_SETTER); |
728 |
break; |
break; |
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 |
|
instrument_expression(node->pn_kid, f); |
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 * push_node; |
|
|
JSParseNode * if_node = NULL; |
|
|
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 |
|
|
877 |
uint16_t line = node->pn_pos.begin.lineno; |
uint16_t line = node->pn_pos.begin.lineno; |
878 |
if (! is_jscoverage_if) { |
if (! is_jscoverage_if) { |
879 |
if (line > num_lines) { |
if (line > num_lines) { |
880 |
fatal("%s: script contains more than 65,535 lines", file_id); |
fatal("file %s contains more than 65,535 lines", file_id); |
881 |
} |
} |
882 |
if (line >= 2 && exclusive_directives[line - 2]) { |
if (line >= 2 && exclusive_directives[line - 2]) { |
883 |
is_jscoverage_if = true; |
is_jscoverage_if = true; |
925 |
Stream_write_string(f, "switch ("); |
Stream_write_string(f, "switch ("); |
926 |
instrument_expression(node->pn_left, f); |
instrument_expression(node->pn_left, f); |
927 |
Stream_write_string(f, ") {\n"); |
Stream_write_string(f, ") {\n"); |
928 |
for (struct JSParseNode * p = node->pn_right->pn_head; p != NULL; p = p->pn_next) { |
{ |
929 |
Stream_printf(f, "%*s", indent, ""); |
JSParseNode * list = node->pn_right; |
930 |
switch (p->pn_type) { |
if (list->pn_type == TOK_LEXICALSCOPE) { |
931 |
case TOK_CASE: |
list = list->pn_expr; |
932 |
Stream_write_string(f, "case "); |
} |
933 |
instrument_expression(p->pn_left, f); |
for (struct JSParseNode * p = list->pn_head; p != NULL; p = p->pn_next) { |
934 |
Stream_write_string(f, ":\n"); |
Stream_printf(f, "%*s", indent, ""); |
935 |
break; |
switch (p->pn_type) { |
936 |
case TOK_DEFAULT: |
case TOK_CASE: |
937 |
Stream_write_string(f, "default:\n"); |
Stream_write_string(f, "case "); |
938 |
break; |
instrument_expression(p->pn_left, f); |
939 |
default: |
Stream_write_string(f, ":\n"); |
940 |
abort(); |
break; |
941 |
break; |
case TOK_DEFAULT: |
942 |
|
Stream_write_string(f, "default:\n"); |
943 |
|
break; |
944 |
|
default: |
945 |
|
abort(); |
946 |
|
break; |
947 |
|
} |
948 |
|
instrument_statement(p->pn_right, f, indent + 2, false); |
949 |
} |
} |
|
instrument_statement(p->pn_right, f, indent + 2, false); |
|
950 |
} |
} |
951 |
Stream_printf(f, "%*s", indent, ""); |
Stream_printf(f, "%*s", indent, ""); |
952 |
Stream_write_string(f, "}\n"); |
Stream_write_string(f, "}\n"); |
1168 |
break; |
break; |
1169 |
} |
} |
1170 |
break; |
break; |
1171 |
|
case TOK_DEBUGGER: |
1172 |
|
Stream_printf(f, "%*s", indent, ""); |
1173 |
|
Stream_write_string(f, "debugger;\n"); |
1174 |
|
break; |
1175 |
default: |
default: |
1176 |
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); |
1177 |
} |
} |
1178 |
} |
} |
1179 |
|
|
1186 |
if (node->pn_type != TOK_LC && node->pn_type != TOK_LEXICALSCOPE) { |
if (node->pn_type != TOK_LC && node->pn_type != TOK_LEXICALSCOPE) { |
1187 |
uint16_t line = node->pn_pos.begin.lineno; |
uint16_t line = node->pn_pos.begin.lineno; |
1188 |
if (line > num_lines) { |
if (line > num_lines) { |
1189 |
fatal("%s: script contains more than 65,535 lines", file_id); |
fatal("file %s contains more than 65,535 lines", file_id); |
1190 |
} |
} |
1191 |
|
|
1192 |
/* the root node has line number 0 */ |
/* the root node has line number 0 */ |
1234 |
} |
} |
1235 |
|
|
1236 |
static void error_reporter(JSContext * context, const char * message, JSErrorReport * report) { |
static void error_reporter(JSContext * context, const char * message, JSErrorReport * report) { |
1237 |
fprintf(stderr, "jscoverage: parse error: line %u: %s\n", report->lineno, message); |
warn_source(file_id, report->lineno, "%s", message); |
1238 |
} |
} |
1239 |
|
|
1240 |
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) { |
1243 |
/* parse the javascript */ |
/* parse the javascript */ |
1244 |
JSParseContext parse_context; |
JSParseContext parse_context; |
1245 |
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)) { |
1246 |
fatal("cannot create token stream from file: %s", file_id); |
fatal("cannot create token stream from file %s", file_id); |
1247 |
} |
} |
1248 |
JSErrorReporter old_error_reporter = JS_SetErrorReporter(context, error_reporter); |
JSErrorReporter old_error_reporter = JS_SetErrorReporter(context, error_reporter); |
1249 |
JSParseNode * node = js_ParseScript(context, global, &parse_context); |
JSParseNode * node = js_ParseScript(context, global, &parse_context); |
1250 |
if (node == NULL) { |
if (node == NULL) { |
1251 |
js_ReportUncaughtException(context); |
js_ReportUncaughtException(context); |
1252 |
fatal("parse error in file: %s", file_id); |
fatal("parse error in file %s", file_id); |
1253 |
} |
} |
1254 |
JS_SetErrorReporter(context, old_error_reporter); |
JS_SetErrorReporter(context, old_error_reporter); |
1255 |
num_lines = node->pn_pos.end.lineno; |
num_lines = node->pn_pos.end.lineno; |
1270 |
size_t i = 0; |
size_t i = 0; |
1271 |
while (i < num_characters) { |
while (i < num_characters) { |
1272 |
if (line_number == UINT16_MAX) { |
if (line_number == UINT16_MAX) { |
1273 |
fatal("%s: script has more than 65,535 lines", file_id); |
fatal("file %s contains more than 65,535 lines", file_id); |
1274 |
} |
} |
1275 |
line_number++; |
line_number++; |
1276 |
size_t line_start = i; |
size_t line_start = i; |
1337 |
|
|
1338 |
/* write line number info to the output */ |
/* write line number info to the output */ |
1339 |
Stream_write_string(output, "/* automatically generated by JSCoverage - do not edit */\n"); |
Stream_write_string(output, "/* automatically generated by JSCoverage - do not edit */\n"); |
1340 |
Stream_write_string(output, "if (! top._$jscoverage) {\n top._$jscoverage = {};\n}\n"); |
if (jscoverage_mozilla) { |
1341 |
Stream_write_string(output, "var _$jscoverage = top._$jscoverage;\n"); |
Stream_write_string(output, "try {\n"); |
1342 |
|
Stream_write_string(output, " Components.utils.import('resource://gre/modules/jscoverage.jsm');\n"); |
1343 |
|
Stream_printf(output, " dump('%s: successfully imported jscoverage module\\n');\n", id); |
1344 |
|
Stream_write_string(output, "}\n"); |
1345 |
|
Stream_write_string(output, "catch (e) {\n"); |
1346 |
|
Stream_write_string(output, " _$jscoverage = {};\n"); |
1347 |
|
Stream_printf(output, " dump('%s: failed to import jscoverage module - coverage not available for this file\\n');\n", id); |
1348 |
|
Stream_write_string(output, "}\n"); |
1349 |
|
} |
1350 |
|
else { |
1351 |
|
Stream_write_string(output, "if (! top._$jscoverage) {\n top._$jscoverage = {};\n}\n"); |
1352 |
|
Stream_write_string(output, "var _$jscoverage = top._$jscoverage;\n"); |
1353 |
|
} |
1354 |
Stream_printf(output, "if (! _$jscoverage['%s']) {\n", file_id); |
Stream_printf(output, "if (! _$jscoverage['%s']) {\n", file_id); |
1355 |
Stream_printf(output, " _$jscoverage['%s'] = [];\n", file_id); |
Stream_printf(output, " _$jscoverage['%s'] = [];\n", file_id); |
1356 |
for (int i = 0; i < num_lines; i++) { |
for (int i = 0; i < num_lines; i++) { |