/[jscoverage]/trunk/instrument-js.c
ViewVC logotype

Annotation of /trunk/instrument-js.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 374 - (hide annotations)
Mon Oct 27 21:42:58 2008 UTC (11 years ago) by siliconforks
File MIME type: text/plain
File size: 53570 byte(s)
Parenthesize object literal in destructuring assignment.
1 siliconforks 2 /*
2     instrument-js.c - JavaScript instrumentation routines
3 siliconforks 87 Copyright (C) 2007, 2008 siliconforks.com
4 siliconforks 2
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9    
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13     GNU General Public License for more details.
14    
15     You should have received a copy of the GNU General Public License along
16     with this program; if not, write to the Free Software Foundation, Inc.,
17     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18     */
19    
20 siliconforks 116 #include <config.h>
21    
22 siliconforks 2 #include "instrument-js.h"
23    
24     #include <assert.h>
25     #include <stdlib.h>
26     #include <string.h>
27    
28     #include <jsapi.h>
29 siliconforks 336 #include <jsarena.h>
30 siliconforks 2 #include <jsatom.h>
31 siliconforks 351 #include <jsemit.h>
32 siliconforks 284 #include <jsexn.h>
33 siliconforks 2 #include <jsfun.h>
34     #include <jsinterp.h>
35 siliconforks 339 #include <jsiter.h>
36 siliconforks 2 #include <jsparse.h>
37     #include <jsregexp.h>
38     #include <jsscope.h>
39     #include <jsstr.h>
40    
41 siliconforks 174 #include "encoding.h"
42 siliconforks 179 #include "global.h"
43     #include "highlight.h"
44 siliconforks 116 #include "resource-manager.h"
45 siliconforks 2 #include "util.h"
46    
47 siliconforks 240 struct IfDirective {
48     const jschar * condition_start;
49     const jschar * condition_end;
50     uint16_t start_line;
51     uint16_t end_line;
52     struct IfDirective * next;
53     };
54    
55 siliconforks 361 bool jscoverage_mozilla = false;
56    
57 siliconforks 240 static bool * exclusive_directives = NULL;
58    
59 siliconforks 2 static JSRuntime * runtime = NULL;
60     static JSContext * context = NULL;
61     static JSObject * global = NULL;
62 siliconforks 339 static JSVersion js_version = JSVERSION_ECMA_3;
63 siliconforks 2
64     /*
65     JSParseNode objects store line numbers starting from 1.
66     The lines array stores line numbers starting from 0.
67     */
68     static const char * file_id = NULL;
69     static char * lines = NULL;
70 siliconforks 214 static uint16_t num_lines = 0;
71 siliconforks 2
72 siliconforks 339 void jscoverage_set_js_version(const char * version) {
73 siliconforks 369 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 siliconforks 370 if ((size_t) (end - version) != strlen(version)) {
81 siliconforks 369 fatal("invalid version: %s", version);
82     }
83 siliconforks 339 }
84    
85 siliconforks 2 void jscoverage_init(void) {
86     runtime = JS_NewRuntime(8L * 1024L * 1024L);
87     if (runtime == NULL) {
88     fatal("cannot create runtime");
89     }
90    
91     context = JS_NewContext(runtime, 8192);
92     if (context == NULL) {
93     fatal("cannot create context");
94     }
95    
96 siliconforks 339 JS_SetVersion(context, js_version);
97    
98 siliconforks 2 global = JS_NewObject(context, NULL, NULL, NULL);
99     if (global == NULL) {
100     fatal("cannot create global object");
101     }
102    
103     if (! JS_InitStandardClasses(context, global)) {
104     fatal("cannot initialize standard classes");
105     }
106     }
107    
108     void jscoverage_cleanup(void) {
109     JS_DestroyContext(context);
110     JS_DestroyRuntime(runtime);
111     }
112    
113 siliconforks 246 static void print_javascript(const jschar * characters, size_t num_characters, Stream * f) {
114     for (size_t i = 0; i < num_characters; i++) {
115     jschar c = characters[i];
116     /*
117     XXX does not handle no-break space, other unicode "space separator"
118     */
119     switch (c) {
120     case 0x9:
121     case 0xB:
122     case 0xC:
123     Stream_write_char(f, c);
124     break;
125     default:
126     if (32 <= c && c <= 126) {
127     Stream_write_char(f, c);
128     }
129     else {
130     Stream_printf(f, "\\u%04x", c);
131     }
132     break;
133     }
134     }
135     }
136    
137 siliconforks 92 static void print_string(JSString * s, Stream * f) {
138 siliconforks 174 size_t length = JSSTRING_LENGTH(s);
139     jschar * characters = JSSTRING_CHARS(s);
140     for (size_t i = 0; i < length; i++) {
141     jschar c = characters[i];
142     if (32 <= c && c <= 126) {
143     switch (c) {
144     case '"':
145     Stream_write_string(f, "\\\"");
146     break;
147     /*
148     case '\'':
149     Stream_write_string(f, "\\'");
150     break;
151     */
152     case '\\':
153     Stream_write_string(f, "\\\\");
154     break;
155     default:
156     Stream_write_char(f, c);
157     break;
158     }
159     }
160     else {
161     switch (c) {
162     case 0x8:
163     Stream_write_string(f, "\\b");
164     break;
165     case 0x9:
166     Stream_write_string(f, "\\t");
167     break;
168     case 0xa:
169     Stream_write_string(f, "\\n");
170     break;
171 siliconforks 317 /* IE doesn't support this */
172     /*
173 siliconforks 174 case 0xb:
174     Stream_write_string(f, "\\v");
175     break;
176 siliconforks 317 */
177 siliconforks 174 case 0xc:
178     Stream_write_string(f, "\\f");
179     break;
180     case 0xd:
181     Stream_write_string(f, "\\r");
182     break;
183     default:
184     Stream_printf(f, "\\u%04x", c);
185     break;
186     }
187     }
188 siliconforks 2 }
189     }
190    
191 siliconforks 92 static void print_string_atom(JSAtom * atom, Stream * f) {
192 siliconforks 2 assert(ATOM_IS_STRING(atom));
193     JSString * s = ATOM_TO_STRING(atom);
194     print_string(s, f);
195     }
196    
197 siliconforks 174 static void print_regex(jsval value, Stream * f) {
198 siliconforks 2 assert(JSVAL_IS_STRING(value));
199     JSString * s = JSVAL_TO_STRING(value);
200 siliconforks 174 size_t length = JSSTRING_LENGTH(s);
201     jschar * characters = JSSTRING_CHARS(s);
202     for (size_t i = 0; i < length; i++) {
203     jschar c = characters[i];
204     if (32 <= c && c <= 126) {
205     Stream_write_char(f, c);
206     }
207     else {
208     Stream_printf(f, "\\u%04x", c);
209     }
210     }
211 siliconforks 2 }
212    
213 siliconforks 92 static void print_quoted_string_atom(JSAtom * atom, Stream * f) {
214 siliconforks 2 assert(ATOM_IS_STRING(atom));
215     JSString * s = ATOM_TO_STRING(atom);
216 siliconforks 174 Stream_write_char(f, '"');
217     print_string(s, f);
218     Stream_write_char(f, '"');
219 siliconforks 2 }
220    
221     static const char * get_op(uint8 op) {
222     switch(op) {
223 siliconforks 336 case JSOP_OR:
224     return "||";
225     case JSOP_AND:
226     return "&&";
227 siliconforks 2 case JSOP_BITOR:
228     return "|";
229     case JSOP_BITXOR:
230     return "^";
231     case JSOP_BITAND:
232     return "&";
233     case JSOP_EQ:
234     return "==";
235     case JSOP_NE:
236     return "!=";
237 siliconforks 336 case JSOP_STRICTEQ:
238 siliconforks 2 return "===";
239 siliconforks 336 case JSOP_STRICTNE:
240 siliconforks 2 return "!==";
241     case JSOP_LT:
242     return "<";
243     case JSOP_LE:
244     return "<=";
245     case JSOP_GT:
246     return ">";
247     case JSOP_GE:
248     return ">=";
249     case JSOP_LSH:
250     return "<<";
251     case JSOP_RSH:
252     return ">>";
253     case JSOP_URSH:
254     return ">>>";
255     case JSOP_ADD:
256     return "+";
257     case JSOP_SUB:
258     return "-";
259     case JSOP_MUL:
260     return "*";
261     case JSOP_DIV:
262     return "/";
263     case JSOP_MOD:
264     return "%";
265     default:
266     abort();
267     }
268     }
269    
270 siliconforks 92 static void instrument_expression(JSParseNode * node, Stream * f);
271 siliconforks 240 static void instrument_statement(JSParseNode * node, Stream * f, int indent, bool is_jscoverage_if);
272 siliconforks 345 static void output_statement(JSParseNode * node, Stream * f, int indent, bool is_jscoverage_if);
273 siliconforks 2
274 siliconforks 155 enum FunctionType {
275     FUNCTION_NORMAL,
276     FUNCTION_GETTER_OR_SETTER
277     };
278    
279 siliconforks 346 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 siliconforks 357 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 siliconforks 155 static void instrument_function(JSParseNode * node, Stream * f, int indent, enum FunctionType type) {
329 siliconforks 336 assert(node->pn_type == TOK_FUNCTION);
330 siliconforks 156 assert(node->pn_arity == PN_FUNC);
331 siliconforks 336 JSObject * object = node->pn_funpob->object;
332 siliconforks 156 assert(JS_ObjectIsFunction(context, object));
333     JSFunction * function = (JSFunction *) JS_GetPrivate(context, object);
334     assert(function);
335 siliconforks 336 assert(object == &function->object);
336 siliconforks 156 Stream_printf(f, "%*s", indent, "");
337     if (type == FUNCTION_NORMAL) {
338 siliconforks 371 Stream_write_string(f, "function ");
339 siliconforks 156 }
340 siliconforks 2
341 siliconforks 156 /* function name */
342     if (function->atom) {
343     print_string_atom(function->atom, f);
344     }
345 siliconforks 2
346 siliconforks 336 /*
347     function parameters - see JS_DecompileFunction in jsapi.cpp, which calls
348     js_DecompileFunction in jsopcode.cpp
349     */
350 siliconforks 371 Stream_write_char(f, '(');
351 siliconforks 336 JSArenaPool pool;
352     JS_INIT_ARENA_POOL(&pool, "instrument_function", 256, 1, &context->scriptStackQuota);
353     jsuword * local_names = NULL;
354     if (JS_GET_LOCAL_NAME_COUNT(function)) {
355     local_names = js_GetLocalNameArray(context, function, &pool);
356     if (local_names == NULL) {
357     fatal("out of memory");
358 siliconforks 2 }
359 siliconforks 156 }
360 siliconforks 373 bool destructuring = false;
361 siliconforks 156 for (int i = 0; i < function->nargs; i++) {
362     if (i > 0) {
363     Stream_write_string(f, ", ");
364 siliconforks 2 }
365 siliconforks 336 JSAtom * param = JS_LOCAL_NAME_TO_ATOM(local_names[i]);
366 siliconforks 352 if (param == NULL) {
367 siliconforks 373 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 siliconforks 352 }
386 siliconforks 373 else {
387     print_string_atom(param, f);
388     }
389 siliconforks 156 }
390 siliconforks 336 JS_FinishArenaPool(&pool);
391 siliconforks 156 Stream_write_string(f, ") {\n");
392 siliconforks 2
393 siliconforks 156 /* function body */
394 siliconforks 345 if (function->flags & JSFUN_EXPR_CLOSURE) {
395 siliconforks 373 /* 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 siliconforks 345 }
405     else {
406 siliconforks 373 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 siliconforks 345 }
416 siliconforks 2
417 siliconforks 156 Stream_write_string(f, "}\n");
418 siliconforks 2 }
419    
420 siliconforks 92 static void instrument_function_call(JSParseNode * node, Stream * f) {
421 siliconforks 351 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 siliconforks 357 output_array_comprehension_or_generator_expression(function_node->pn_body, f);
433 siliconforks 351 Stream_write_char(f, ')');
434     return;
435 siliconforks 2 }
436 siliconforks 351 else {
437     Stream_write_char(f, '(');
438     instrument_expression(function_node, f);
439 siliconforks 346 Stream_write_char(f, ')');
440     }
441 siliconforks 2 }
442 siliconforks 346 else {
443 siliconforks 351 instrument_expression(function_node, f);
444     }
445     Stream_write_char(f, '(');
446     for (struct JSParseNode * p = function_node->pn_next; p != NULL; p = p->pn_next) {
447     if (p != node->pn_head->pn_next) {
448     Stream_write_string(f, ", ");
449 siliconforks 346 }
450 siliconforks 351 instrument_expression(p, f);
451 siliconforks 346 }
452 siliconforks 351 Stream_write_char(f, ')');
453 siliconforks 2 }
454    
455 siliconforks 340 static void instrument_declarations(JSParseNode * list, Stream * f) {
456     assert(list->pn_arity == PN_LIST);
457     for (JSParseNode * p = list->pn_head; p != NULL; p = p->pn_next) {
458 siliconforks 341 switch (p->pn_type) {
459     case TOK_NAME:
460     assert(p->pn_arity == PN_NAME);
461     if (p != list->pn_head) {
462     Stream_write_string(f, ", ");
463     }
464     print_string_atom(p->pn_atom, f);
465     if (p->pn_expr != NULL) {
466     Stream_write_string(f, " = ");
467     instrument_expression(p->pn_expr, f);
468     }
469     break;
470     case TOK_ASSIGN:
471 siliconforks 374 /* destructuring */
472     instrument_expression(p->pn_left, f);
473     Stream_write_string(f, " = ");
474     instrument_expression(p->pn_right, f);
475     break;
476 siliconforks 341 case TOK_RB:
477     case TOK_RC:
478     /* destructuring */
479     instrument_expression(p, f);
480     break;
481     default:
482     abort();
483     break;
484 siliconforks 340 }
485     }
486     }
487    
488 siliconforks 2 /*
489     See <Expressions> in jsparse.h.
490     TOK_FUNCTION is handled as a statement and as an expression.
491     TOK_DBLDOT is not handled (XML op).
492     TOK_DEFSHARP and TOK_USESHARP are not handled.
493     TOK_ANYNAME is not handled (XML op).
494     TOK_AT is not handled (XML op).
495     TOK_DBLCOLON is not handled.
496     TOK_XML* are not handled.
497     There seem to be some undocumented expressions:
498     TOK_INSTANCEOF binary
499     TOK_IN binary
500     */
501 siliconforks 92 static void instrument_expression(JSParseNode * node, Stream * f) {
502 siliconforks 2 switch (node->pn_type) {
503     case TOK_FUNCTION:
504 siliconforks 155 instrument_function(node, f, 0, FUNCTION_NORMAL);
505 siliconforks 2 break;
506     case TOK_COMMA:
507     for (struct JSParseNode * p = node->pn_head; p != NULL; p = p->pn_next) {
508     if (p != node->pn_head) {
509 siliconforks 92 Stream_write_string(f, ", ");
510 siliconforks 2 }
511     instrument_expression(p, f);
512     }
513     break;
514     case TOK_ASSIGN:
515 siliconforks 374 if (node->pn_left->pn_type == TOK_RC) {
516     /* destructuring assignment with object literal must be in parentheses */
517     Stream_write_char(f, '(');
518     instrument_expression(node->pn_left, f);
519     Stream_write_char(f, ')');
520     }
521     else {
522     instrument_expression(node->pn_left, f);
523     }
524 siliconforks 92 Stream_write_char(f, ' ');
525 siliconforks 2 switch (node->pn_op) {
526     case JSOP_ADD:
527     case JSOP_SUB:
528     case JSOP_MUL:
529     case JSOP_MOD:
530     case JSOP_LSH:
531     case JSOP_RSH:
532     case JSOP_URSH:
533     case JSOP_BITAND:
534     case JSOP_BITOR:
535     case JSOP_BITXOR:
536     case JSOP_DIV:
537 siliconforks 92 Stream_printf(f, "%s", get_op(node->pn_op));
538 siliconforks 2 break;
539     default:
540     /* do nothing - it must be a simple assignment */
541     break;
542     }
543 siliconforks 92 Stream_write_string(f, "= ");
544 siliconforks 2 instrument_expression(node->pn_right, f);
545     break;
546     case TOK_HOOK:
547     instrument_expression(node->pn_kid1, f);
548 siliconforks 92 Stream_write_string(f, "? ");
549 siliconforks 2 instrument_expression(node->pn_kid2, f);
550 siliconforks 92 Stream_write_string(f, ": ");
551 siliconforks 2 instrument_expression(node->pn_kid3, f);
552     break;
553     case TOK_OR:
554     case TOK_AND:
555     case TOK_BITOR:
556     case TOK_BITXOR:
557     case TOK_BITAND:
558     case TOK_EQOP:
559     case TOK_RELOP:
560     case TOK_SHOP:
561     case TOK_PLUS:
562     case TOK_MINUS:
563     case TOK_STAR:
564     case TOK_DIVOP:
565     switch (node->pn_arity) {
566     case PN_BINARY:
567     instrument_expression(node->pn_left, f);
568 siliconforks 92 Stream_printf(f, " %s ", get_op(node->pn_op));
569 siliconforks 2 instrument_expression(node->pn_right, f);
570     break;
571     case PN_LIST:
572     for (struct JSParseNode * p = node->pn_head; p != NULL; p = p->pn_next) {
573     if (p != node->pn_head) {
574 siliconforks 92 Stream_printf(f, " %s ", get_op(node->pn_op));
575 siliconforks 2 }
576     instrument_expression(p, f);
577     }
578     break;
579     default:
580     abort();
581     }
582     break;
583     case TOK_UNARYOP:
584     switch (node->pn_op) {
585     case JSOP_NEG:
586 siliconforks 92 Stream_write_char(f, '-');
587 siliconforks 2 instrument_expression(node->pn_kid, f);
588     break;
589     case JSOP_POS:
590 siliconforks 92 Stream_write_char(f, '+');
591 siliconforks 2 instrument_expression(node->pn_kid, f);
592     break;
593     case JSOP_NOT:
594 siliconforks 92 Stream_write_char(f, '!');
595 siliconforks 2 instrument_expression(node->pn_kid, f);
596     break;
597     case JSOP_BITNOT:
598 siliconforks 92 Stream_write_char(f, '~');
599 siliconforks 2 instrument_expression(node->pn_kid, f);
600     break;
601     case JSOP_TYPEOF:
602 siliconforks 92 Stream_write_string(f, "typeof ");
603 siliconforks 2 instrument_expression(node->pn_kid, f);
604     break;
605     case JSOP_VOID:
606 siliconforks 92 Stream_write_string(f, "void ");
607 siliconforks 2 instrument_expression(node->pn_kid, f);
608     break;
609     default:
610 siliconforks 370 fatal_source(file_id, node->pn_pos.begin.lineno, "unknown operator (%d)", node->pn_op);
611 siliconforks 2 break;
612     }
613     break;
614     case TOK_INC:
615     case TOK_DEC:
616     /*
617     This is not documented, but node->pn_op tells whether it is pre- or post-increment.
618     */
619     switch (node->pn_op) {
620     case JSOP_INCNAME:
621     case JSOP_INCPROP:
622     case JSOP_INCELEM:
623 siliconforks 92 Stream_write_string(f, "++");
624 siliconforks 2 instrument_expression(node->pn_kid, f);
625     break;
626     case JSOP_DECNAME:
627     case JSOP_DECPROP:
628     case JSOP_DECELEM:
629 siliconforks 92 Stream_write_string(f, "--");
630 siliconforks 2 instrument_expression(node->pn_kid, f);
631     break;
632     case JSOP_NAMEINC:
633     case JSOP_PROPINC:
634     case JSOP_ELEMINC:
635     instrument_expression(node->pn_kid, f);
636 siliconforks 92 Stream_write_string(f, "++");
637 siliconforks 2 break;
638     case JSOP_NAMEDEC:
639     case JSOP_PROPDEC:
640     case JSOP_ELEMDEC:
641     instrument_expression(node->pn_kid, f);
642 siliconforks 92 Stream_write_string(f, "--");
643 siliconforks 2 break;
644     default:
645     abort();
646     break;
647     }
648     break;
649     case TOK_NEW:
650 siliconforks 92 Stream_write_string(f, "new ");
651 siliconforks 2 instrument_function_call(node, f);
652     break;
653     case TOK_DELETE:
654 siliconforks 92 Stream_write_string(f, "delete ");
655 siliconforks 2 instrument_expression(node->pn_kid, f);
656     break;
657     case TOK_DOT:
658     /*
659     This may have originally been x['foo-bar']. Because the string 'foo-bar'
660     contains illegal characters, we have to use the subscript syntax instead of
661     the dot syntax.
662     */
663     instrument_expression(node->pn_expr, f);
664 siliconforks 84 assert(ATOM_IS_STRING(node->pn_atom));
665     {
666     JSString * s = ATOM_TO_STRING(node->pn_atom);
667 siliconforks 349 bool must_quote;
668     if (JSSTRING_LENGTH(s) == 0) {
669     must_quote = true;
670 siliconforks 84 }
671 siliconforks 349 else if (js_CheckKeyword(JSSTRING_CHARS(s), JSSTRING_LENGTH(s)) != TOK_EOF) {
672     must_quote = true;
673     }
674     else if (! js_IsIdentifier(s)) {
675     must_quote = true;
676     }
677 siliconforks 84 else {
678 siliconforks 349 must_quote = false;
679     }
680     if (must_quote) {
681 siliconforks 92 Stream_write_char(f, '[');
682 siliconforks 84 print_quoted_string_atom(node->pn_atom, f);
683 siliconforks 92 Stream_write_char(f, ']');
684 siliconforks 84 }
685 siliconforks 349 else {
686     Stream_write_char(f, '.');
687     print_string_atom(node->pn_atom, f);
688     }
689 siliconforks 84 }
690 siliconforks 2 break;
691     case TOK_LB:
692     instrument_expression(node->pn_left, f);
693 siliconforks 92 Stream_write_char(f, '[');
694 siliconforks 2 instrument_expression(node->pn_right, f);
695 siliconforks 92 Stream_write_char(f, ']');
696 siliconforks 2 break;
697     case TOK_LP:
698     instrument_function_call(node, f);
699     break;
700     case TOK_RB:
701 siliconforks 92 Stream_write_char(f, '[');
702 siliconforks 2 for (struct JSParseNode * p = node->pn_head; p != NULL; p = p->pn_next) {
703     if (p != node->pn_head) {
704 siliconforks 92 Stream_write_string(f, ", ");
705 siliconforks 2 }
706     /* TOK_COMMA is a special case: a hole in the array */
707     if (p->pn_type != TOK_COMMA) {
708     instrument_expression(p, f);
709     }
710     }
711     if (node->pn_extra == PNX_ENDCOMMA) {
712 siliconforks 92 Stream_write_char(f, ',');
713 siliconforks 2 }
714 siliconforks 92 Stream_write_char(f, ']');
715 siliconforks 2 break;
716     case TOK_RC:
717 siliconforks 92 Stream_write_char(f, '{');
718 siliconforks 2 for (struct JSParseNode * p = node->pn_head; p != NULL; p = p->pn_next) {
719 siliconforks 353 if (p->pn_type != TOK_COLON) {
720 siliconforks 370 fatal_source(file_id, p->pn_pos.begin.lineno, "unsupported node type (%d)", p->pn_type);
721 siliconforks 353 }
722 siliconforks 2 if (p != node->pn_head) {
723 siliconforks 92 Stream_write_string(f, ", ");
724 siliconforks 2 }
725 siliconforks 155
726     /* check whether this is a getter or setter */
727     switch (p->pn_op) {
728     case JSOP_GETTER:
729     case JSOP_SETTER:
730 siliconforks 293 if (p->pn_op == JSOP_GETTER) {
731     Stream_write_string(f, "get ");
732     }
733     else {
734     Stream_write_string(f, "set ");
735     }
736 siliconforks 155 instrument_expression(p->pn_left, f);
737 siliconforks 293 if (p->pn_right->pn_type != TOK_FUNCTION) {
738 siliconforks 370 fatal_source(file_id, p->pn_pos.begin.lineno, "expected function");
739 siliconforks 293 }
740 siliconforks 155 instrument_function(p->pn_right, f, 0, FUNCTION_GETTER_OR_SETTER);
741     break;
742     default:
743     instrument_expression(p->pn_left, f);
744     Stream_write_string(f, ": ");
745     instrument_expression(p->pn_right, f);
746     break;
747     }
748 siliconforks 2 }
749 siliconforks 92 Stream_write_char(f, '}');
750 siliconforks 2 break;
751     case TOK_RP:
752 siliconforks 92 Stream_write_char(f, '(');
753 siliconforks 2 instrument_expression(node->pn_kid, f);
754 siliconforks 92 Stream_write_char(f, ')');
755 siliconforks 2 break;
756     case TOK_NAME:
757     print_string_atom(node->pn_atom, f);
758     break;
759     case TOK_STRING:
760     print_quoted_string_atom(node->pn_atom, f);
761     break;
762 siliconforks 336 case TOK_REGEXP:
763     assert(node->pn_op == JSOP_REGEXP);
764     {
765     JSObject * object = node->pn_pob->object;
766     jsval result;
767     js_regexp_toString(context, object, &result);
768     print_regex(result, f);
769 siliconforks 2 }
770     break;
771     case TOK_NUMBER:
772     /*
773     A 64-bit IEEE 754 floating point number has a 52-bit fraction.
774     2^(-52) = 2.22 x 10^(-16)
775     Thus there are 16 significant digits.
776     To keep the output simple, special-case zero.
777     */
778     if (node->pn_dval == 0.0) {
779 siliconforks 92 Stream_write_string(f, "0");
780 siliconforks 2 }
781     else {
782 siliconforks 92 Stream_printf(f, "%.15g", node->pn_dval);
783 siliconforks 2 }
784     break;
785     case TOK_PRIMARY:
786     switch (node->pn_op) {
787     case JSOP_TRUE:
788 siliconforks 92 Stream_write_string(f, "true");
789 siliconforks 2 break;
790     case JSOP_FALSE:
791 siliconforks 92 Stream_write_string(f, "false");
792 siliconforks 2 break;
793     case JSOP_NULL:
794 siliconforks 92 Stream_write_string(f, "null");
795 siliconforks 2 break;
796     case JSOP_THIS:
797 siliconforks 92 Stream_write_string(f, "this");
798 siliconforks 2 break;
799     /* jsscan.h mentions `super' ??? */
800     default:
801     abort();
802     }
803     break;
804     case TOK_INSTANCEOF:
805     instrument_expression(node->pn_left, f);
806 siliconforks 92 Stream_write_string(f, " instanceof ");
807 siliconforks 2 instrument_expression(node->pn_right, f);
808     break;
809     case TOK_IN:
810     instrument_expression(node->pn_left, f);
811 siliconforks 92 Stream_write_string(f, " in ");
812 siliconforks 2 instrument_expression(node->pn_right, f);
813     break;
814 siliconforks 340 case TOK_LEXICALSCOPE:
815     assert(node->pn_arity == PN_NAME);
816     assert(node->pn_expr->pn_type == TOK_LET);
817     assert(node->pn_expr->pn_arity == PN_BINARY);
818     Stream_write_string(f, "let(");
819     assert(node->pn_expr->pn_left->pn_type == TOK_LP);
820     assert(node->pn_expr->pn_left->pn_arity == PN_LIST);
821     instrument_declarations(node->pn_expr->pn_left, f);
822     Stream_write_string(f, ") ");
823     instrument_expression(node->pn_expr->pn_right, f);
824     break;
825 siliconforks 342 case TOK_YIELD:
826     assert(node->pn_arity == PN_UNARY);
827 siliconforks 355 Stream_write_string(f, "yield");
828     if (node->pn_kid != NULL) {
829     Stream_write_char(f, ' ');
830     instrument_expression(node->pn_kid, f);
831     }
832 siliconforks 342 break;
833 siliconforks 343 case TOK_ARRAYCOMP:
834     assert(node->pn_arity == PN_LIST);
835     {
836     JSParseNode * block_node;
837     switch (node->pn_count) {
838     case 1:
839     block_node = node->pn_head;
840     break;
841     case 2:
842     block_node = node->pn_head->pn_next;
843     break;
844     default:
845     abort();
846     break;
847     }
848     Stream_write_char(f, '[');
849 siliconforks 357 output_array_comprehension_or_generator_expression(block_node, f);
850 siliconforks 343 Stream_write_char(f, ']');
851     }
852     break;
853     case TOK_VAR:
854     assert(node->pn_arity == PN_LIST);
855     Stream_write_string(f, "var ");
856     instrument_declarations(node, f);
857     break;
858     case TOK_LET:
859     assert(node->pn_arity == PN_LIST);
860     Stream_write_string(f, "let ");
861     instrument_declarations(node, f);
862     break;
863 siliconforks 2 default:
864 siliconforks 370 fatal_source(file_id, node->pn_pos.begin.lineno, "unsupported node type (%d)", node->pn_type);
865 siliconforks 2 }
866     }
867    
868 siliconforks 240 static void output_statement(JSParseNode * node, Stream * f, int indent, bool is_jscoverage_if) {
869 siliconforks 2 switch (node->pn_type) {
870     case TOK_FUNCTION:
871 siliconforks 155 instrument_function(node, f, indent, FUNCTION_NORMAL);
872 siliconforks 2 break;
873     case TOK_LC:
874     assert(node->pn_arity == PN_LIST);
875     /*
876 siliconforks 92 Stream_write_string(f, "{\n");
877 siliconforks 2 */
878     for (struct JSParseNode * p = node->pn_u.list.head; p != NULL; p = p->pn_next) {
879 siliconforks 240 instrument_statement(p, f, indent, false);
880 siliconforks 2 }
881     /*
882 siliconforks 92 Stream_printf(f, "%*s", indent, "");
883     Stream_write_string(f, "}\n");
884 siliconforks 2 */
885     break;
886     case TOK_IF:
887 siliconforks 240 {
888 siliconforks 2 assert(node->pn_arity == PN_TERNARY);
889 siliconforks 240
890     uint16_t line = node->pn_pos.begin.lineno;
891     if (! is_jscoverage_if) {
892     if (line > num_lines) {
893 siliconforks 370 fatal("file %s contains more than 65,535 lines", file_id);
894 siliconforks 240 }
895     if (line >= 2 && exclusive_directives[line - 2]) {
896     is_jscoverage_if = true;
897     }
898     }
899    
900 siliconforks 92 Stream_printf(f, "%*s", indent, "");
901     Stream_write_string(f, "if (");
902 siliconforks 2 instrument_expression(node->pn_kid1, f);
903 siliconforks 92 Stream_write_string(f, ") {\n");
904 siliconforks 240 if (is_jscoverage_if && node->pn_kid3) {
905     uint16_t else_start = node->pn_kid3->pn_pos.begin.lineno;
906     uint16_t else_end = node->pn_kid3->pn_pos.end.lineno + 1;
907     Stream_printf(f, "%*s", indent + 2, "");
908     Stream_printf(f, "_$jscoverage['%s'].conditionals[%d] = %d;\n", file_id, else_start, else_end);
909     }
910     instrument_statement(node->pn_kid2, f, indent + 2, false);
911 siliconforks 92 Stream_printf(f, "%*s", indent, "");
912     Stream_write_string(f, "}\n");
913 siliconforks 240
914     if (node->pn_kid3 || is_jscoverage_if) {
915 siliconforks 92 Stream_printf(f, "%*s", indent, "");
916     Stream_write_string(f, "else {\n");
917 siliconforks 240
918     if (is_jscoverage_if) {
919     uint16_t if_start = node->pn_kid2->pn_pos.begin.lineno + 1;
920     uint16_t if_end = node->pn_kid2->pn_pos.end.lineno + 1;
921     Stream_printf(f, "%*s", indent + 2, "");
922     Stream_printf(f, "_$jscoverage['%s'].conditionals[%d] = %d;\n", file_id, if_start, if_end);
923     }
924    
925     if (node->pn_kid3) {
926     instrument_statement(node->pn_kid3, f, indent + 2, is_jscoverage_if);
927     }
928    
929 siliconforks 92 Stream_printf(f, "%*s", indent, "");
930     Stream_write_string(f, "}\n");
931 siliconforks 2 }
932 siliconforks 240
933 siliconforks 2 break;
934 siliconforks 240 }
935 siliconforks 2 case TOK_SWITCH:
936     assert(node->pn_arity == PN_BINARY);
937 siliconforks 92 Stream_printf(f, "%*s", indent, "");
938     Stream_write_string(f, "switch (");
939 siliconforks 2 instrument_expression(node->pn_left, f);
940 siliconforks 92 Stream_write_string(f, ") {\n");
941 siliconforks 350 {
942     JSParseNode * list = node->pn_right;
943     if (list->pn_type == TOK_LEXICALSCOPE) {
944     list = list->pn_expr;
945 siliconforks 2 }
946 siliconforks 350 for (struct JSParseNode * p = list->pn_head; p != NULL; p = p->pn_next) {
947     Stream_printf(f, "%*s", indent, "");
948     switch (p->pn_type) {
949     case TOK_CASE:
950     Stream_write_string(f, "case ");
951     instrument_expression(p->pn_left, f);
952     Stream_write_string(f, ":\n");
953     break;
954     case TOK_DEFAULT:
955     Stream_write_string(f, "default:\n");
956     break;
957     default:
958     abort();
959     break;
960     }
961     instrument_statement(p->pn_right, f, indent + 2, false);
962     }
963 siliconforks 2 }
964 siliconforks 92 Stream_printf(f, "%*s", indent, "");
965     Stream_write_string(f, "}\n");
966 siliconforks 2 break;
967     case TOK_CASE:
968     case TOK_DEFAULT:
969     abort();
970     break;
971     case TOK_WHILE:
972     assert(node->pn_arity == PN_BINARY);
973 siliconforks 92 Stream_printf(f, "%*s", indent, "");
974     Stream_write_string(f, "while (");
975 siliconforks 2 instrument_expression(node->pn_left, f);
976 siliconforks 92 Stream_write_string(f, ") {\n");
977 siliconforks 240 instrument_statement(node->pn_right, f, indent + 2, false);
978 siliconforks 92 Stream_write_string(f, "}\n");
979 siliconforks 2 break;
980     case TOK_DO:
981     assert(node->pn_arity == PN_BINARY);
982 siliconforks 92 Stream_printf(f, "%*s", indent, "");
983     Stream_write_string(f, "do {\n");
984 siliconforks 240 instrument_statement(node->pn_left, f, indent + 2, false);
985 siliconforks 92 Stream_write_string(f, "}\n");
986     Stream_printf(f, "%*s", indent, "");
987     Stream_write_string(f, "while (");
988 siliconforks 2 instrument_expression(node->pn_right, f);
989 siliconforks 92 Stream_write_string(f, ");\n");
990 siliconforks 2 break;
991     case TOK_FOR:
992     assert(node->pn_arity == PN_BINARY);
993 siliconforks 92 Stream_printf(f, "%*s", indent, "");
994 siliconforks 2 switch (node->pn_left->pn_type) {
995     case TOK_IN:
996     /* for/in */
997     assert(node->pn_left->pn_arity == PN_BINARY);
998 siliconforks 343 output_for_in(node, f);
999 siliconforks 2 break;
1000     case TOK_RESERVED:
1001     /* for (;;) */
1002     assert(node->pn_left->pn_arity == PN_TERNARY);
1003 siliconforks 343 Stream_write_string(f, "for (");
1004 siliconforks 2 if (node->pn_left->pn_kid1) {
1005 siliconforks 343 instrument_expression(node->pn_left->pn_kid1, f);
1006 siliconforks 2 }
1007 siliconforks 92 Stream_write_string(f, ";");
1008 siliconforks 2 if (node->pn_left->pn_kid2) {
1009 siliconforks 92 Stream_write_char(f, ' ');
1010 siliconforks 2 instrument_expression(node->pn_left->pn_kid2, f);
1011     }
1012 siliconforks 92 Stream_write_string(f, ";");
1013 siliconforks 2 if (node->pn_left->pn_kid3) {
1014 siliconforks 92 Stream_write_char(f, ' ');
1015 siliconforks 2 instrument_expression(node->pn_left->pn_kid3, f);
1016     }
1017 siliconforks 343 Stream_write_char(f, ')');
1018 siliconforks 2 break;
1019     default:
1020     abort();
1021     break;
1022     }
1023 siliconforks 343 Stream_write_string(f, " {\n");
1024 siliconforks 240 instrument_statement(node->pn_right, f, indent + 2, false);
1025 siliconforks 92 Stream_write_string(f, "}\n");
1026 siliconforks 2 break;
1027     case TOK_THROW:
1028     assert(node->pn_arity == PN_UNARY);
1029 siliconforks 92 Stream_printf(f, "%*s", indent, "");
1030     Stream_write_string(f, "throw ");
1031 siliconforks 2 instrument_expression(node->pn_u.unary.kid, f);
1032 siliconforks 92 Stream_write_string(f, ";\n");
1033 siliconforks 2 break;
1034     case TOK_TRY:
1035 siliconforks 92 Stream_printf(f, "%*s", indent, "");
1036     Stream_write_string(f, "try {\n");
1037 siliconforks 240 instrument_statement(node->pn_kid1, f, indent + 2, false);
1038 siliconforks 92 Stream_printf(f, "%*s", indent, "");
1039     Stream_write_string(f, "}\n");
1040 siliconforks 336 if (node->pn_kid2) {
1041     assert(node->pn_kid2->pn_type == TOK_RESERVED);
1042     for (JSParseNode * scope = node->pn_kid2->pn_head; scope != NULL; scope = scope->pn_next) {
1043     assert(scope->pn_type == TOK_LEXICALSCOPE);
1044     JSParseNode * catch = scope->pn_expr;
1045 siliconforks 2 assert(catch->pn_type == TOK_CATCH);
1046 siliconforks 92 Stream_printf(f, "%*s", indent, "");
1047     Stream_write_string(f, "catch (");
1048 siliconforks 341 /* this may not be a name - destructuring assignment */
1049     /*
1050 siliconforks 2 assert(catch->pn_kid1->pn_arity == PN_NAME);
1051     print_string_atom(catch->pn_kid1->pn_atom, f);
1052 siliconforks 341 */
1053     instrument_expression(catch->pn_kid1, f);
1054 siliconforks 336 if (catch->pn_kid2) {
1055 siliconforks 92 Stream_write_string(f, " if ");
1056 siliconforks 336 instrument_expression(catch->pn_kid2, f);
1057 siliconforks 2 }
1058 siliconforks 92 Stream_write_string(f, ") {\n");
1059 siliconforks 240 instrument_statement(catch->pn_kid3, f, indent + 2, false);
1060 siliconforks 92 Stream_printf(f, "%*s", indent, "");
1061     Stream_write_string(f, "}\n");
1062 siliconforks 2 }
1063     }
1064     if (node->pn_kid3) {
1065 siliconforks 92 Stream_printf(f, "%*s", indent, "");
1066     Stream_write_string(f, "finally {\n");
1067 siliconforks 240 instrument_statement(node->pn_kid3, f, indent + 2, false);
1068 siliconforks 92 Stream_printf(f, "%*s", indent, "");
1069     Stream_write_string(f, "}\n");
1070 siliconforks 2 }
1071     break;
1072     case TOK_CATCH:
1073     abort();
1074     break;
1075     case TOK_BREAK:
1076     case TOK_CONTINUE:
1077     assert(node->pn_arity == PN_NAME || node->pn_arity == PN_NULLARY);
1078 siliconforks 92 Stream_printf(f, "%*s", indent, "");
1079     Stream_write_string(f, node->pn_type == TOK_BREAK? "break": "continue");
1080 siliconforks 2 JSAtom * atom = node->pn_u.name.atom;
1081     if (atom != NULL) {
1082 siliconforks 92 Stream_write_char(f, ' ');
1083 siliconforks 2 print_string_atom(node->pn_atom, f);
1084     }
1085 siliconforks 92 Stream_write_string(f, ";\n");
1086 siliconforks 2 break;
1087     case TOK_WITH:
1088     assert(node->pn_arity == PN_BINARY);
1089 siliconforks 92 Stream_printf(f, "%*s", indent, "");
1090     Stream_write_string(f, "with (");
1091 siliconforks 2 instrument_expression(node->pn_left, f);
1092 siliconforks 92 Stream_write_string(f, ") {\n");
1093 siliconforks 240 instrument_statement(node->pn_right, f, indent + 2, false);
1094 siliconforks 92 Stream_printf(f, "%*s", indent, "");
1095     Stream_write_string(f, "}\n");
1096 siliconforks 2 break;
1097     case TOK_VAR:
1098 siliconforks 343 Stream_printf(f, "%*s", indent, "");
1099     instrument_expression(node, f);
1100 siliconforks 92 Stream_write_string(f, ";\n");
1101 siliconforks 2 break;
1102     case TOK_RETURN:
1103     assert(node->pn_arity == PN_UNARY);
1104 siliconforks 92 Stream_printf(f, "%*s", indent, "");
1105     Stream_write_string(f, "return");
1106 siliconforks 2 if (node->pn_kid != NULL) {
1107 siliconforks 92 Stream_write_char(f, ' ');
1108 siliconforks 2 instrument_expression(node->pn_kid, f);
1109     }
1110 siliconforks 92 Stream_write_string(f, ";\n");
1111 siliconforks 2 break;
1112     case TOK_SEMI:
1113     assert(node->pn_arity == PN_UNARY);
1114 siliconforks 92 Stream_printf(f, "%*s", indent, "");
1115 siliconforks 2 if (node->pn_kid != NULL) {
1116     instrument_expression(node->pn_kid, f);
1117     }
1118 siliconforks 92 Stream_write_string(f, ";\n");
1119 siliconforks 2 break;
1120     case TOK_COLON:
1121     assert(node->pn_arity == PN_NAME);
1122     /*
1123     This one is tricky: can't output instrumentation between the label and the
1124     statement it's supposed to label ...
1125     */
1126 siliconforks 92 Stream_printf(f, "%*s", indent < 2? 0: indent - 2, "");
1127 siliconforks 2 print_string_atom(node->pn_atom, f);
1128 siliconforks 92 Stream_write_string(f, ":\n");
1129 siliconforks 2 /*
1130     ... use output_statement instead of instrument_statement.
1131     */
1132 siliconforks 240 output_statement(node->pn_expr, f, indent, false);
1133 siliconforks 2 break;
1134 siliconforks 340 case TOK_LEXICALSCOPE:
1135     /* let statement */
1136     assert(node->pn_arity == PN_NAME);
1137     switch (node->pn_expr->pn_type) {
1138     case TOK_LET:
1139     /* let statement */
1140     assert(node->pn_expr->pn_arity == PN_BINARY);
1141     instrument_statement(node->pn_expr, f, indent, false);
1142     break;
1143     case TOK_LC:
1144     /* block */
1145     Stream_printf(f, "%*s", indent, "");
1146     Stream_write_string(f, "{\n");
1147     instrument_statement(node->pn_expr, f, indent + 2, false);
1148     Stream_printf(f, "%*s", indent, "");
1149     Stream_write_string(f, "}\n");
1150     break;
1151     case TOK_FOR:
1152     instrument_statement(node->pn_expr, f, indent, false);
1153     break;
1154     default:
1155     abort();
1156     break;
1157     }
1158     break;
1159     case TOK_LET:
1160     switch (node->pn_arity) {
1161     case PN_BINARY:
1162     /* let statement */
1163     Stream_printf(f, "%*s", indent, "");
1164     Stream_write_string(f, "let (");
1165     assert(node->pn_left->pn_type == TOK_LP);
1166     assert(node->pn_left->pn_arity == PN_LIST);
1167     instrument_declarations(node->pn_left, f);
1168     Stream_write_string(f, ") {\n");
1169     instrument_statement(node->pn_right, f, indent + 2, false);
1170     Stream_printf(f, "%*s", indent, "");
1171     Stream_write_string(f, "}\n");
1172     break;
1173     case PN_LIST:
1174     /* let definition */
1175 siliconforks 343 Stream_printf(f, "%*s", indent, "");
1176     instrument_expression(node, f);
1177 siliconforks 340 Stream_write_string(f, ";\n");
1178     break;
1179     default:
1180     abort();
1181     break;
1182     }
1183     break;
1184 siliconforks 348 case TOK_DEBUGGER:
1185     Stream_printf(f, "%*s", indent, "");
1186     Stream_write_string(f, "debugger;\n");
1187     break;
1188 siliconforks 2 default:
1189 siliconforks 370 fatal_source(file_id, node->pn_pos.begin.lineno, "unsupported node type (%d)", node->pn_type);
1190 siliconforks 2 }
1191     }
1192    
1193     /*
1194     See <Statements> in jsparse.h.
1195     TOK_FUNCTION is handled as a statement and as an expression.
1196     TOK_EXPORT, TOK_IMPORT are not handled.
1197     */
1198 siliconforks 240 static void instrument_statement(JSParseNode * node, Stream * f, int indent, bool is_jscoverage_if) {
1199 siliconforks 340 if (node->pn_type != TOK_LC && node->pn_type != TOK_LEXICALSCOPE) {
1200 siliconforks 214 uint16_t line = node->pn_pos.begin.lineno;
1201     if (line > num_lines) {
1202 siliconforks 370 fatal("file %s contains more than 65,535 lines", file_id);
1203 siliconforks 214 }
1204    
1205 siliconforks 2 /* the root node has line number 0 */
1206     if (line != 0) {
1207 siliconforks 92 Stream_printf(f, "%*s", indent, "");
1208     Stream_printf(f, "_$jscoverage['%s'][%d]++;\n", file_id, line);
1209 siliconforks 2 lines[line - 1] = 1;
1210     }
1211     }
1212 siliconforks 240 output_statement(node, f, indent, is_jscoverage_if);
1213 siliconforks 2 }
1214    
1215 siliconforks 190 static bool characters_start_with(const jschar * characters, size_t line_start, size_t line_end, const char * prefix) {
1216     const jschar * characters_end = characters + line_end;
1217     const jschar * cp = characters + line_start;
1218     const char * bp = prefix;
1219     for (;;) {
1220     if (*bp == '\0') {
1221     return true;
1222     }
1223     else if (cp == characters_end) {
1224     return false;
1225     }
1226     else if (*cp != *bp) {
1227     return false;
1228     }
1229     bp++;
1230     cp++;
1231     }
1232     }
1233    
1234 siliconforks 240 static bool characters_are_white_space(const jschar * characters, size_t line_start, size_t line_end) {
1235     /* XXX - other Unicode space */
1236     const jschar * end = characters + line_end;
1237     for (const jschar * p = characters + line_start; p < end; p++) {
1238     jschar c = *p;
1239     if (c == 0x9 || c == 0xB || c == 0xC || c == 0x20 || c == 0xA0) {
1240     continue;
1241     }
1242     else {
1243     return false;
1244     }
1245     }
1246     return true;
1247     }
1248    
1249 siliconforks 284 static void error_reporter(JSContext * context, const char * message, JSErrorReport * report) {
1250 siliconforks 372 warn_source(file_id, report->lineno, "%s", message);
1251 siliconforks 284 }
1252    
1253 siliconforks 179 void jscoverage_instrument_js(const char * id, const uint16_t * characters, size_t num_characters, Stream * output) {
1254 siliconforks 2 file_id = id;
1255    
1256 siliconforks 336 /* parse the javascript */
1257     JSParseContext parse_context;
1258     if (! js_InitParseContext(context, &parse_context, NULL, NULL, characters, num_characters, NULL, NULL, 1)) {
1259 siliconforks 370 fatal("cannot create token stream from file %s", file_id);
1260 siliconforks 2 }
1261 siliconforks 284 JSErrorReporter old_error_reporter = JS_SetErrorReporter(context, error_reporter);
1262 siliconforks 336 JSParseNode * node = js_ParseScript(context, global, &parse_context);
1263 siliconforks 2 if (node == NULL) {
1264 siliconforks 284 js_ReportUncaughtException(context);
1265 siliconforks 370 fatal("parse error in file %s", file_id);
1266 siliconforks 2 }
1267 siliconforks 284 JS_SetErrorReporter(context, old_error_reporter);
1268 siliconforks 214 num_lines = node->pn_pos.end.lineno;
1269 siliconforks 2 lines = xmalloc(num_lines);
1270 siliconforks 240 for (unsigned int i = 0; i < num_lines; i++) {
1271 siliconforks 2 lines[i] = 0;
1272     }
1273    
1274 siliconforks 240 /* search code for conditionals */
1275     exclusive_directives = xnew(bool, num_lines);
1276     for (unsigned int i = 0; i < num_lines; i++) {
1277     exclusive_directives[i] = false;
1278 siliconforks 2 }
1279    
1280 siliconforks 157 bool has_conditionals = false;
1281 siliconforks 240 struct IfDirective * if_directives = NULL;
1282 siliconforks 157 size_t line_number = 0;
1283     size_t i = 0;
1284 siliconforks 176 while (i < num_characters) {
1285 siliconforks 240 if (line_number == UINT16_MAX) {
1286 siliconforks 370 fatal("file %s contains more than 65,535 lines", file_id);
1287 siliconforks 240 }
1288 siliconforks 157 line_number++;
1289     size_t line_start = i;
1290 siliconforks 190 jschar c;
1291     bool done = false;
1292     while (! done && i < num_characters) {
1293     c = characters[i];
1294     switch (c) {
1295     case '\r':
1296     case '\n':
1297     case 0x2028:
1298     case 0x2029:
1299     done = true;
1300     break;
1301     default:
1302     i++;
1303     }
1304 siliconforks 157 }
1305     size_t line_end = i;
1306 siliconforks 176 if (i < num_characters) {
1307 siliconforks 190 i++;
1308     if (c == '\r' && i < num_characters && characters[i] == '\n') {
1309 siliconforks 157 i++;
1310     }
1311     }
1312 siliconforks 240
1313 siliconforks 190 if (characters_start_with(characters, line_start, line_end, "//#JSCOVERAGE_IF")) {
1314 siliconforks 240 has_conditionals = true;
1315    
1316     if (characters_are_white_space(characters, line_start + 16, line_end)) {
1317     exclusive_directives[line_number - 1] = true;
1318 siliconforks 157 }
1319 siliconforks 240 else {
1320     struct IfDirective * if_directive = xnew(struct IfDirective, 1);
1321     if_directive->condition_start = characters + line_start + 16;
1322     if_directive->condition_end = characters + line_end;
1323     if_directive->start_line = line_number;
1324     if_directive->end_line = 0;
1325     if_directive->next = if_directives;
1326     if_directives = if_directive;
1327 siliconforks 190 }
1328 siliconforks 157 }
1329 siliconforks 190 else if (characters_start_with(characters, line_start, line_end, "//#JSCOVERAGE_ENDIF")) {
1330 siliconforks 240 for (struct IfDirective * p = if_directives; p != NULL; p = p->next) {
1331     if (p->end_line == 0) {
1332     p->end_line = line_number;
1333     break;
1334     }
1335     }
1336 siliconforks 157 }
1337     }
1338    
1339 siliconforks 240 /*
1340     An instrumented JavaScript file has 4 sections:
1341     1. initialization
1342     2. instrumented source code
1343     3. conditionals
1344     4. original source code
1345     */
1346    
1347     Stream * instrumented = Stream_new(0);
1348     instrument_statement(node, instrumented, 0, false);
1349 siliconforks 336 js_FinishParseContext(context, &parse_context);
1350 siliconforks 240
1351     /* write line number info to the output */
1352     Stream_write_string(output, "/* automatically generated by JSCoverage - do not edit */\n");
1353 siliconforks 361 if (jscoverage_mozilla) {
1354     Stream_write_string(output, "try {\n");
1355     Stream_write_string(output, " Components.utils.import('resource://gre/modules/jscoverage.jsm');\n");
1356     Stream_printf(output, " dump('%s: successfully imported jscoverage module\\n');\n", id);
1357     Stream_write_string(output, "}\n");
1358     Stream_write_string(output, "catch (e) {\n");
1359     Stream_write_string(output, " _$jscoverage = {};\n");
1360     Stream_printf(output, " dump('%s: failed to import jscoverage module - coverage not available for this file\\n');\n", id);
1361     Stream_write_string(output, "}\n");
1362     }
1363     else {
1364     Stream_write_string(output, "if (! top._$jscoverage) {\n top._$jscoverage = {};\n}\n");
1365     Stream_write_string(output, "var _$jscoverage = top._$jscoverage;\n");
1366     }
1367 siliconforks 240 Stream_printf(output, "if (! _$jscoverage['%s']) {\n", file_id);
1368     Stream_printf(output, " _$jscoverage['%s'] = [];\n", file_id);
1369     for (int i = 0; i < num_lines; i++) {
1370     if (lines[i]) {
1371     Stream_printf(output, " _$jscoverage['%s'][%d] = 0;\n", file_id, i + 1);
1372     }
1373     }
1374     Stream_write_string(output, "}\n");
1375     free(lines);
1376     lines = NULL;
1377     free(exclusive_directives);
1378     exclusive_directives = NULL;
1379    
1380     /* conditionals */
1381     if (has_conditionals) {
1382     Stream_printf(output, "_$jscoverage['%s'].conditionals = [];\n", file_id);
1383     }
1384    
1385     /* copy the instrumented source code to the output */
1386     Stream_write(output, instrumented->data, instrumented->length);
1387    
1388     /* conditionals */
1389     for (struct IfDirective * if_directive = if_directives; if_directive != NULL; if_directive = if_directive->next) {
1390     Stream_write_string(output, "if (!(");
1391 siliconforks 246 print_javascript(if_directive->condition_start, if_directive->condition_end - if_directive->condition_start, output);
1392 siliconforks 240 Stream_write_string(output, ")) {\n");
1393     Stream_printf(output, " _$jscoverage['%s'].conditionals[%d] = %d;\n", file_id, if_directive->start_line, if_directive->end_line);
1394     Stream_write_string(output, "}\n");
1395     }
1396    
1397     /* free */
1398     while (if_directives != NULL) {
1399     struct IfDirective * if_directive = if_directives;
1400     if_directives = if_directives->next;
1401     free(if_directive);
1402     }
1403    
1404 siliconforks 95 /* copy the original source to the output */
1405 siliconforks 179 Stream_printf(output, "_$jscoverage['%s'].source = ", file_id);
1406     jscoverage_write_source(id, characters, num_characters, output);
1407     Stream_printf(output, ";\n");
1408 siliconforks 95
1409 siliconforks 179 Stream_delete(instrumented);
1410    
1411     file_id = NULL;
1412     }
1413    
1414     void jscoverage_write_source(const char * id, const jschar * characters, size_t num_characters, Stream * output) {
1415     Stream_write_string(output, "[");
1416     if (jscoverage_highlight) {
1417     Stream * highlighted_stream = Stream_new(num_characters);
1418     jscoverage_highlight_js(context, id, characters, num_characters, highlighted_stream);
1419     size_t i = 0;
1420     while (i < highlighted_stream->length) {
1421     if (i > 0) {
1422     Stream_write_char(output, ',');
1423     }
1424    
1425     Stream_write_char(output, '"');
1426     bool done = false;
1427     while (! done) {
1428     char c = highlighted_stream->data[i];
1429     switch (c) {
1430     case 0x8:
1431     /* backspace */
1432     Stream_write_string(output, "\\b");
1433     break;
1434     case 0x9:
1435     /* horizontal tab */
1436     Stream_write_string(output, "\\t");
1437     break;
1438     case 0xa:
1439     /* line feed (new line) */
1440     done = true;
1441     break;
1442 siliconforks 317 /* IE doesn't support this */
1443     /*
1444 siliconforks 179 case 0xb:
1445     Stream_write_string(output, "\\v");
1446     break;
1447 siliconforks 317 */
1448 siliconforks 179 case 0xc:
1449     /* form feed */
1450     Stream_write_string(output, "\\f");
1451     break;
1452     case 0xd:
1453     /* carriage return */
1454     done = true;
1455     if (i + 1 < highlighted_stream->length && highlighted_stream->data[i + 1] == '\n') {
1456     i++;
1457     }
1458     break;
1459     case '"':
1460     Stream_write_string(output, "\\\"");
1461     break;
1462     case '\\':
1463     Stream_write_string(output, "\\\\");
1464     break;
1465     default:
1466     Stream_write_char(output, c);
1467     break;
1468     }
1469 siliconforks 95 i++;
1470 siliconforks 179 if (i >= highlighted_stream->length) {
1471     done = true;
1472 siliconforks 95 }
1473     }
1474 siliconforks 179 Stream_write_char(output, '"');
1475     }
1476     Stream_delete(highlighted_stream);
1477     }
1478     else {
1479     size_t i = 0;
1480     while (i < num_characters) {
1481     if (i > 0) {
1482     Stream_write_char(output, ',');
1483     }
1484    
1485     Stream_write_char(output, '"');
1486     bool done = false;
1487     while (! done) {
1488     jschar c = characters[i];
1489     switch (c) {
1490     case 0x8:
1491     /* backspace */
1492     Stream_write_string(output, "\\b");
1493     break;
1494     case 0x9:
1495     /* horizontal tab */
1496     Stream_write_string(output, "\\t");
1497     break;
1498     case 0xa:
1499     /* line feed (new line) */
1500     done = true;
1501     break;
1502 siliconforks 317 /* IE doesn't support this */
1503     /*
1504 siliconforks 179 case 0xb:
1505     Stream_write_string(output, "\\v");
1506     break;
1507 siliconforks 317 */
1508 siliconforks 179 case 0xc:
1509     /* form feed */
1510     Stream_write_string(output, "\\f");
1511     break;
1512     case 0xd:
1513     /* carriage return */
1514     done = true;
1515     if (i + 1 < num_characters && characters[i + 1] == '\n') {
1516     i++;
1517     }
1518     break;
1519     case '"':
1520     Stream_write_string(output, "\\\"");
1521     break;
1522     case '\\':
1523     Stream_write_string(output, "\\\\");
1524     break;
1525     case '&':
1526     Stream_write_string(output, "&amp;");
1527     break;
1528     case '<':
1529     Stream_write_string(output, "&lt;");
1530     break;
1531     case '>':
1532     Stream_write_string(output, "&gt;");
1533     break;
1534     case 0x2028:
1535     case 0x2029:
1536     done = true;
1537     break;
1538     default:
1539     if (32 <= c && c <= 126) {
1540     Stream_write_char(output, c);
1541     }
1542     else {
1543     Stream_printf(output, "&#%d;", c);
1544     }
1545     break;
1546     }
1547 siliconforks 95 i++;
1548 siliconforks 179 if (i >= num_characters) {
1549     done = true;
1550     }
1551 siliconforks 95 }
1552 siliconforks 179 Stream_write_char(output, '"');
1553 siliconforks 95 }
1554     }
1555 siliconforks 179 Stream_write_string(output, "]");
1556 siliconforks 2 }
1557 siliconforks 116
1558     void jscoverage_copy_resources(const char * destination_directory) {
1559     copy_resource("jscoverage.html", destination_directory);
1560     copy_resource("jscoverage.css", destination_directory);
1561     copy_resource("jscoverage.js", destination_directory);
1562 siliconforks 169 copy_resource("jscoverage-ie.css", destination_directory);
1563 siliconforks 116 copy_resource("jscoverage-throbber.gif", destination_directory);
1564 siliconforks 179 copy_resource("jscoverage-highlight.css", destination_directory);
1565 siliconforks 116 }
1566    
1567     /*
1568     coverage reports
1569     */
1570    
1571     struct FileCoverageList {
1572     FileCoverage * file_coverage;
1573     struct FileCoverageList * next;
1574     };
1575    
1576     struct Coverage {
1577     JSHashTable * coverage_table;
1578     struct FileCoverageList * coverage_list;
1579     };
1580    
1581     static int compare_strings(const void * p1, const void * p2) {
1582     return strcmp(p1, p2) == 0;
1583     }
1584    
1585     Coverage * Coverage_new(void) {
1586     Coverage * result = xmalloc(sizeof(Coverage));
1587     result->coverage_table = JS_NewHashTable(1024, JS_HashString, compare_strings, NULL, NULL, NULL);
1588     if (result->coverage_table == NULL) {
1589     fatal("cannot create hash table");
1590     }
1591     result->coverage_list = NULL;
1592     return result;
1593     }
1594    
1595     void Coverage_delete(Coverage * coverage) {
1596     JS_HashTableDestroy(coverage->coverage_table);
1597     struct FileCoverageList * p = coverage->coverage_list;
1598     while (p != NULL) {
1599 siliconforks 179 free(p->file_coverage->coverage_lines);
1600     if (p->file_coverage->source_lines != NULL) {
1601     for (uint32 i = 0; i < p->file_coverage->num_source_lines; i++) {
1602     free(p->file_coverage->source_lines[i]);
1603     }
1604     free(p->file_coverage->source_lines);
1605     }
1606 siliconforks 116 free(p->file_coverage->id);
1607     free(p->file_coverage);
1608     struct FileCoverageList * q = p;
1609     p = p->next;
1610     free(q);
1611     }
1612     free(coverage);
1613     }
1614    
1615     struct EnumeratorArg {
1616     CoverageForeachFunction f;
1617     void * p;
1618     };
1619    
1620     static intN enumerator(JSHashEntry * entry, intN i, void * arg) {
1621     struct EnumeratorArg * enumerator_arg = arg;
1622     enumerator_arg->f(entry->value, i, enumerator_arg->p);
1623     return 0;
1624     }
1625    
1626     void Coverage_foreach_file(Coverage * coverage, CoverageForeachFunction f, void * p) {
1627     struct EnumeratorArg enumerator_arg;
1628     enumerator_arg.f = f;
1629     enumerator_arg.p = p;
1630     JS_HashTableEnumerateEntries(coverage->coverage_table, enumerator, &enumerator_arg);
1631     }
1632    
1633     int jscoverage_parse_json(Coverage * coverage, const uint8_t * json, size_t length) {
1634 siliconforks 336 int result = 0;
1635    
1636 siliconforks 116 jschar * base = js_InflateString(context, (char *) json, &length);
1637     if (base == NULL) {
1638     fatal("out of memory");
1639     }
1640    
1641     jschar * parenthesized_json = xnew(jschar, addst(length, 2));
1642     parenthesized_json[0] = '(';
1643     memcpy(parenthesized_json + 1, base, mulst(length, sizeof(jschar)));
1644     parenthesized_json[length + 1] = ')';
1645    
1646     JS_free(context, base);
1647    
1648 siliconforks 336 JSParseContext parse_context;
1649     if (! js_InitParseContext(context, &parse_context, NULL, NULL, parenthesized_json, length + 2, NULL, NULL, 1)) {
1650     free(parenthesized_json);
1651     return -1;
1652 siliconforks 116 }
1653 siliconforks 336 JSParseNode * root = js_ParseScript(context, global, &parse_context);
1654 siliconforks 116 free(parenthesized_json);
1655     if (root == NULL) {
1656 siliconforks 336 result = -1;
1657     goto done;
1658 siliconforks 116 }
1659    
1660     /* root node must be TOK_LC */
1661     if (root->pn_type != TOK_LC) {
1662 siliconforks 336 result = -1;
1663     goto done;
1664 siliconforks 116 }
1665     JSParseNode * semi = root->pn_u.list.head;
1666    
1667     /* the list must be TOK_SEMI and it must contain only one element */
1668     if (semi->pn_type != TOK_SEMI || semi->pn_next != NULL) {
1669 siliconforks 336 result = -1;
1670     goto done;
1671 siliconforks 116 }
1672     JSParseNode * parenthesized = semi->pn_kid;
1673    
1674     /* this must be a parenthesized expression */
1675     if (parenthesized->pn_type != TOK_RP) {
1676 siliconforks 336 result = -1;
1677     goto done;
1678 siliconforks 116 }
1679     JSParseNode * object = parenthesized->pn_kid;
1680    
1681     /* this must be an object literal */
1682     if (object->pn_type != TOK_RC) {
1683 siliconforks 336 result = -1;
1684     goto done;
1685 siliconforks 116 }
1686    
1687     for (JSParseNode * p = object->pn_head; p != NULL; p = p->pn_next) {
1688     /* every element of this list must be TOK_COLON */
1689     if (p->pn_type != TOK_COLON) {
1690 siliconforks 336 result = -1;
1691     goto done;
1692 siliconforks 116 }
1693    
1694     /* the key must be a string representing the file */
1695     JSParseNode * key = p->pn_left;
1696     if (key->pn_type != TOK_STRING || ! ATOM_IS_STRING(key->pn_atom)) {
1697 siliconforks 336 result = -1;
1698     goto done;
1699 siliconforks 116 }
1700     char * id_bytes = JS_GetStringBytes(ATOM_TO_STRING(key->pn_atom));
1701    
1702     /* the value must be an object literal OR an array */
1703     JSParseNode * value = p->pn_right;
1704     if (! (value->pn_type == TOK_RC || value->pn_type == TOK_RB)) {
1705 siliconforks 336 result = -1;
1706     goto done;
1707 siliconforks 116 }
1708    
1709     JSParseNode * array = NULL;
1710     JSParseNode * source = NULL;
1711     if (value->pn_type == TOK_RB) {
1712     /* an array */
1713     array = value;
1714     }
1715     else if (value->pn_type == TOK_RC) {
1716     /* an object literal */
1717     if (value->pn_count != 2) {
1718 siliconforks 336 result = -1;
1719     goto done;
1720 siliconforks 116 }
1721     for (JSParseNode * element = value->pn_head; element != NULL; element = element->pn_next) {
1722     if (element->pn_type != TOK_COLON) {
1723 siliconforks 336 result = -1;
1724     goto done;
1725 siliconforks 116 }
1726     JSParseNode * left = element->pn_left;
1727     if (left->pn_type != TOK_STRING || ! ATOM_IS_STRING(left->pn_atom)) {
1728 siliconforks 336 result = -1;
1729     goto done;
1730 siliconforks 116 }
1731     const char * s = JS_GetStringBytes(ATOM_TO_STRING(left->pn_atom));
1732     if (strcmp(s, "coverage") == 0) {
1733     array = element->pn_right;
1734     if (array->pn_type != TOK_RB) {
1735 siliconforks 336 result = -1;
1736     goto done;
1737 siliconforks 116 }
1738     }
1739     else if (strcmp(s, "source") == 0) {
1740     source = element->pn_right;
1741 siliconforks 179 if (source->pn_type != TOK_RB) {
1742 siliconforks 336 result = -1;
1743     goto done;
1744 siliconforks 116 }
1745     }
1746     else {
1747 siliconforks 336 result = -1;
1748     goto done;
1749 siliconforks 116 }
1750     }
1751     }
1752     else {
1753 siliconforks 336 result = -1;
1754     goto done;
1755 siliconforks 116 }
1756    
1757     if (array == NULL) {
1758 siliconforks 336 result = -1;
1759     goto done;
1760 siliconforks 116 }
1761    
1762     /* look up the file in the coverage table */
1763     FileCoverage * file_coverage = JS_HashTableLookup(coverage->coverage_table, id_bytes);
1764     if (file_coverage == NULL) {
1765     /* not there: create a new one */
1766     char * id = xstrdup(id_bytes);
1767     file_coverage = xmalloc(sizeof(FileCoverage));
1768     file_coverage->id = id;
1769 siliconforks 179 file_coverage->num_coverage_lines = array->pn_count;
1770     file_coverage->coverage_lines = xnew(int, array->pn_count);
1771 siliconforks 245 file_coverage->source_lines = NULL;
1772 siliconforks 116
1773     /* set coverage for all lines */
1774     uint32 i = 0;
1775     for (JSParseNode * element = array->pn_head; element != NULL; element = element->pn_next, i++) {
1776     if (element->pn_type == TOK_NUMBER) {
1777 siliconforks 179 file_coverage->coverage_lines[i] = (int) element->pn_dval;
1778 siliconforks 116 }
1779     else if (element->pn_type == TOK_PRIMARY && element->pn_op == JSOP_NULL) {
1780 siliconforks 179 file_coverage->coverage_lines[i] = -1;
1781 siliconforks 116 }
1782     else {
1783 siliconforks 336 result = -1;
1784     goto done;
1785 siliconforks 116 }
1786     }
1787     assert(i == array->pn_count);
1788    
1789     /* add to the hash table */
1790     JS_HashTableAdd(coverage->coverage_table, id, file_coverage);
1791     struct FileCoverageList * coverage_list = xmalloc(sizeof(struct FileCoverageList));
1792     coverage_list->file_coverage = file_coverage;
1793     coverage_list->next = coverage->coverage_list;
1794     coverage->coverage_list = coverage_list;
1795     }
1796     else {
1797     /* sanity check */
1798     assert(strcmp(file_coverage->id, id_bytes) == 0);
1799 siliconforks 179 if (file_coverage->num_coverage_lines != array->pn_count) {
1800 siliconforks 336 result = -2;
1801     goto done;
1802 siliconforks 116 }
1803    
1804     /* merge the coverage */
1805     uint32 i = 0;
1806     for (JSParseNode * element = array->pn_head; element != NULL; element = element->pn_next, i++) {
1807     if (element->pn_type == TOK_NUMBER) {
1808 siliconforks 179 if (file_coverage->coverage_lines[i] == -1) {
1809 siliconforks 336 result = -2;
1810     goto done;
1811 siliconforks 116 }
1812 siliconforks 179 file_coverage->coverage_lines[i] += (int) element->pn_dval;
1813 siliconforks 116 }
1814     else if (element->pn_type == TOK_PRIMARY && element->pn_op == JSOP_NULL) {
1815 siliconforks 179 if (file_coverage->coverage_lines[i] != -1) {
1816 siliconforks 336 result = -2;
1817     goto done;
1818 siliconforks 116 }
1819     }
1820     else {
1821 siliconforks 336 result = -1;
1822     goto done;
1823 siliconforks 116 }
1824     }
1825     assert(i == array->pn_count);
1826 siliconforks 245 }
1827 siliconforks 116
1828 siliconforks 245 /* if this JSON file has source, use it */
1829     if (file_coverage->source_lines == NULL && source != NULL) {
1830     file_coverage->num_source_lines = source->pn_count;
1831     file_coverage->source_lines = xnew(char *, source->pn_count);
1832     uint32 i = 0;
1833     for (JSParseNode * element = source->pn_head; element != NULL; element = element->pn_next, i++) {
1834     if (element->pn_type != TOK_STRING) {
1835 siliconforks 336 result = -1;
1836     goto done;
1837 siliconforks 179 }
1838 siliconforks 245 file_coverage->source_lines[i] = xstrdup(JS_GetStringBytes(ATOM_TO_STRING(element->pn_atom)));
1839 siliconforks 116 }
1840 siliconforks 245 assert(i == source->pn_count);
1841 siliconforks 116 }
1842     }
1843    
1844 siliconforks 336 done:
1845     js_FinishParseContext(context, &parse_context);
1846     return result;
1847 siliconforks 116 }

  ViewVC Help
Powered by ViewVC 1.1.24