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

Diff of /trunk/instrument-js.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 90 by siliconforks, Tue May 6 14:05:12 2008 UTC revision 92 by siliconforks, Wed May 7 04:21:22 2008 UTC
# Line 71  Line 71 
71    JS_DestroyRuntime(runtime);    JS_DestroyRuntime(runtime);
72  }  }
73    
74  static void print_string(JSString * s, FILE * f) {  static void print_string(JSString * s, Stream * f) {
75    for (int i = 0; i < s->length; i++) {    for (int i = 0; i < s->length; i++) {
76      char c = s->chars[i];      char c = s->chars[i];
77      fputc(c, f);      Stream_write_char(f, c);
78    }    }
79  }  }
80    
81  static void print_string_atom(JSAtom * atom, FILE * f) {  static void print_string_atom(JSAtom * atom, Stream * f) {
82    assert(ATOM_IS_STRING(atom));    assert(ATOM_IS_STRING(atom));
83    JSString * s = ATOM_TO_STRING(atom);    JSString * s = ATOM_TO_STRING(atom);
84    print_string(s, f);    print_string(s, f);
85  }  }
86    
87  static void print_string_jsval(jsval value, FILE * f) {  static void print_string_jsval(jsval value, Stream * f) {
88    assert(JSVAL_IS_STRING(value));    assert(JSVAL_IS_STRING(value));
89    JSString * s = JSVAL_TO_STRING(value);    JSString * s = JSVAL_TO_STRING(value);
90    print_string(s, f);    print_string(s, f);
91  }  }
92    
93  static void print_quoted_string_atom(JSAtom * atom, FILE * f) {  static void print_quoted_string_atom(JSAtom * atom, Stream * f) {
94    assert(ATOM_IS_STRING(atom));    assert(ATOM_IS_STRING(atom));
95    JSString * s = ATOM_TO_STRING(atom);    JSString * s = ATOM_TO_STRING(atom);
96    JSString * quoted = js_QuoteString(context, s, '"');    JSString * quoted = js_QuoteString(context, s, '"');
# Line 142  Line 142 
142    }    }
143  }  }
144    
145  static void instrument_expression(JSParseNode * node, FILE * f);  static void instrument_expression(JSParseNode * node, Stream * f);
146  static void instrument_statement(JSParseNode * node, FILE * f, int indent);  static void instrument_statement(JSParseNode * node, Stream * f, int indent);
147    
148  static void instrument_function(JSParseNode * node, FILE * f, int indent) {  static void instrument_function(JSParseNode * node, Stream * f, int indent) {
149      assert(node->pn_arity == PN_FUNC);      assert(node->pn_arity == PN_FUNC);
150      assert(ATOM_IS_OBJECT(node->pn_funAtom));      assert(ATOM_IS_OBJECT(node->pn_funAtom));
151      JSObject * object = ATOM_TO_OBJECT(node->pn_funAtom);      JSObject * object = ATOM_TO_OBJECT(node->pn_funAtom);
# Line 153  Line 153 
153      JSFunction * function = (JSFunction *) JS_GetPrivate(context, object);      JSFunction * function = (JSFunction *) JS_GetPrivate(context, object);
154      assert(function);      assert(function);
155      assert(object == function->object);      assert(object == function->object);
156      fprintf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
157      fprintf(f, "function");      Stream_write_string(f, "function");
158    
159      /* function name */      /* function name */
160      if (function->atom) {      if (function->atom) {
161        fputc(' ', f);        Stream_write_char(f, ' ');
162        print_string_atom(function->atom, f);        print_string_atom(function->atom, f);
163      }      }
164    
165      /* function parameters */      /* function parameters */
166      fprintf(f, "(");      Stream_write_string(f, "(");
167      JSAtom ** params = xmalloc(function->nargs * sizeof(JSAtom *));      JSAtom ** params = xmalloc(function->nargs * sizeof(JSAtom *));
168      for (int i = 0; i < function->nargs; i++) {      for (int i = 0; i < function->nargs; i++) {
169        /* initialize to NULL for sanity check */        /* initialize to NULL for sanity check */
# Line 182  Line 182 
182      for (int i = 0; i < function->nargs; i++) {      for (int i = 0; i < function->nargs; i++) {
183        assert(params[i] != NULL);        assert(params[i] != NULL);
184        if (i > 0) {        if (i > 0) {
185          fprintf(f, ", ");          Stream_write_string(f, ", ");
186        }        }
187        if (ATOM_IS_STRING(params[i])) {        if (ATOM_IS_STRING(params[i])) {
188          print_string_atom(params[i], f);          print_string_atom(params[i], f);
189        }        }
190      }      }
191      fprintf(f, ") {\n");      Stream_write_string(f, ") {\n");
192      free(params);      free(params);
193    
194      /* function body */      /* function body */
195      instrument_statement(node->pn_body, f, indent + 2);      instrument_statement(node->pn_body, f, indent + 2);
196    
197      fprintf(f, "}\n");      Stream_write_string(f, "}\n");
198  }  }
199    
200  static void instrument_function_call(JSParseNode * node, FILE * f) {  static void instrument_function_call(JSParseNode * node, Stream * f) {
201    instrument_expression(node->pn_head, f);    instrument_expression(node->pn_head, f);
202    fputc('(', f);    Stream_write_char(f, '(');
203    for (struct JSParseNode * p = node->pn_head->pn_next; p != NULL; p = p->pn_next) {    for (struct JSParseNode * p = node->pn_head->pn_next; p != NULL; p = p->pn_next) {
204      if (p != node->pn_head->pn_next) {      if (p != node->pn_head->pn_next) {
205        fprintf(f, ", ");        Stream_write_string(f, ", ");
206      }      }
207      instrument_expression(p, f);      instrument_expression(p, f);
208    }    }
209    fputc(')', f);    Stream_write_char(f, ')');
210  }  }
211    
212  /*  /*
# Line 222  Line 222 
222  TOK_INSTANCEOF  binary  TOK_INSTANCEOF  binary
223  TOK_IN          binary  TOK_IN          binary
224  */  */
225  static void instrument_expression(JSParseNode * node, FILE * f) {  static void instrument_expression(JSParseNode * node, Stream * f) {
226    switch (node->pn_type) {    switch (node->pn_type) {
227    case TOK_FUNCTION:    case TOK_FUNCTION:
228      instrument_function(node, f, 0);      instrument_function(node, f, 0);
# Line 230  Line 230 
230    case TOK_COMMA:    case TOK_COMMA:
231      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) {
232        if (p != node->pn_head) {        if (p != node->pn_head) {
233          fprintf(f, ", ");          Stream_write_string(f, ", ");
234        }        }
235        instrument_expression(p, f);        instrument_expression(p, f);
236      }      }
237      break;      break;
238    case TOK_ASSIGN:    case TOK_ASSIGN:
239      instrument_expression(node->pn_left, f);      instrument_expression(node->pn_left, f);
240      fputc(' ', f);      Stream_write_char(f, ' ');
241      switch (node->pn_op) {      switch (node->pn_op) {
242      case JSOP_ADD:      case JSOP_ADD:
243      case JSOP_SUB:      case JSOP_SUB:
# Line 250  Line 250 
250      case JSOP_BITOR:      case JSOP_BITOR:
251      case JSOP_BITXOR:      case JSOP_BITXOR:
252      case JSOP_DIV:      case JSOP_DIV:
253        fprintf(f, "%s", get_op(node->pn_op));        Stream_printf(f, "%s", get_op(node->pn_op));
254        break;        break;
255      default:      default:
256        /* do nothing - it must be a simple assignment */        /* do nothing - it must be a simple assignment */
257        break;        break;
258      }      }
259      fprintf(f, "= ");      Stream_write_string(f, "= ");
260      instrument_expression(node->pn_right, f);      instrument_expression(node->pn_right, f);
261      break;      break;
262    case TOK_HOOK:    case TOK_HOOK:
263      instrument_expression(node->pn_kid1, f);      instrument_expression(node->pn_kid1, f);
264      fprintf(f, "? ");      Stream_write_string(f, "? ");
265      instrument_expression(node->pn_kid2, f);      instrument_expression(node->pn_kid2, f);
266      fprintf(f, ": ");      Stream_write_string(f, ": ");
267      instrument_expression(node->pn_kid3, f);      instrument_expression(node->pn_kid3, f);
268      break;      break;
269    case TOK_OR:    case TOK_OR:
270      instrument_expression(node->pn_left, f);      instrument_expression(node->pn_left, f);
271      fprintf(f, " || ");      Stream_write_string(f, " || ");
272      instrument_expression(node->pn_right, f);      instrument_expression(node->pn_right, f);
273      break;      break;
274    case TOK_AND:    case TOK_AND:
275      instrument_expression(node->pn_left, f);      instrument_expression(node->pn_left, f);
276      fprintf(f, " && ");      Stream_write_string(f, " && ");
277      instrument_expression(node->pn_right, f);      instrument_expression(node->pn_right, f);
278      break;      break;
279    case TOK_BITOR:    case TOK_BITOR:
# Line 289  Line 289 
289      switch (node->pn_arity) {      switch (node->pn_arity) {
290      case PN_BINARY:      case PN_BINARY:
291        instrument_expression(node->pn_left, f);        instrument_expression(node->pn_left, f);
292        fprintf(f, " %s ", get_op(node->pn_op));        Stream_printf(f, " %s ", get_op(node->pn_op));
293        instrument_expression(node->pn_right, f);        instrument_expression(node->pn_right, f);
294        break;        break;
295      case PN_LIST:      case PN_LIST:
296        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) {
297          if (p != node->pn_head) {          if (p != node->pn_head) {
298            fprintf(f, " %s ", get_op(node->pn_op));            Stream_printf(f, " %s ", get_op(node->pn_op));
299          }          }
300          instrument_expression(p, f);          instrument_expression(p, f);
301        }        }
# Line 307  Line 307 
307    case TOK_UNARYOP:    case TOK_UNARYOP:
308      switch (node->pn_op) {      switch (node->pn_op) {
309      case JSOP_NEG:      case JSOP_NEG:
310        fputc('-', f);        Stream_write_char(f, '-');
311        instrument_expression(node->pn_kid, f);        instrument_expression(node->pn_kid, f);
312        break;        break;
313      case JSOP_POS:      case JSOP_POS:
314        fputc('+', f);        Stream_write_char(f, '+');
315        instrument_expression(node->pn_kid, f);        instrument_expression(node->pn_kid, f);
316        break;        break;
317      case JSOP_NOT:      case JSOP_NOT:
318        fputc('!', f);        Stream_write_char(f, '!');
319        instrument_expression(node->pn_kid, f);        instrument_expression(node->pn_kid, f);
320        break;        break;
321      case JSOP_BITNOT:      case JSOP_BITNOT:
322        fputc('~', f);        Stream_write_char(f, '~');
323        instrument_expression(node->pn_kid, f);        instrument_expression(node->pn_kid, f);
324        break;        break;
325      case JSOP_TYPEOF:      case JSOP_TYPEOF:
326        fprintf(f, "typeof ");        Stream_write_string(f, "typeof ");
327        instrument_expression(node->pn_kid, f);        instrument_expression(node->pn_kid, f);
328        break;        break;
329      case JSOP_VOID:      case JSOP_VOID:
330        fprintf(f, "void ");        Stream_write_string(f, "void ");
331        instrument_expression(node->pn_kid, f);        instrument_expression(node->pn_kid, f);
332        break;        break;
333      default:      default:
# Line 344  Line 344 
344      case JSOP_INCNAME:      case JSOP_INCNAME:
345      case JSOP_INCPROP:      case JSOP_INCPROP:
346      case JSOP_INCELEM:      case JSOP_INCELEM:
347        fprintf(f, "++");        Stream_write_string(f, "++");
348        instrument_expression(node->pn_kid, f);        instrument_expression(node->pn_kid, f);
349        break;        break;
350      case JSOP_DECNAME:      case JSOP_DECNAME:
351      case JSOP_DECPROP:      case JSOP_DECPROP:
352      case JSOP_DECELEM:      case JSOP_DECELEM:
353        fprintf(f, "--");        Stream_write_string(f, "--");
354        instrument_expression(node->pn_kid, f);        instrument_expression(node->pn_kid, f);
355        break;        break;
356      case JSOP_NAMEINC:      case JSOP_NAMEINC:
357      case JSOP_PROPINC:      case JSOP_PROPINC:
358      case JSOP_ELEMINC:      case JSOP_ELEMINC:
359        instrument_expression(node->pn_kid, f);        instrument_expression(node->pn_kid, f);
360        fprintf(f, "++");        Stream_write_string(f, "++");
361        break;        break;
362      case JSOP_NAMEDEC:      case JSOP_NAMEDEC:
363      case JSOP_PROPDEC:      case JSOP_PROPDEC:
364      case JSOP_ELEMDEC:      case JSOP_ELEMDEC:
365        instrument_expression(node->pn_kid, f);        instrument_expression(node->pn_kid, f);
366        fprintf(f, "--");        Stream_write_string(f, "--");
367        break;        break;
368      default:      default:
369        abort();        abort();
# Line 371  Line 371 
371      }      }
372      break;      break;
373    case TOK_NEW:    case TOK_NEW:
374      fprintf(f, "new ");      Stream_write_string(f, "new ");
375      instrument_function_call(node, f);      instrument_function_call(node, f);
376      break;      break;
377    case TOK_DELETE:    case TOK_DELETE:
378      fprintf(f, "delete ");      Stream_write_string(f, "delete ");
379      instrument_expression(node->pn_kid, f);      instrument_expression(node->pn_kid, f);
380      break;      break;
381    case TOK_DOT:    case TOK_DOT:
# Line 390  Line 390 
390        JSString * s = ATOM_TO_STRING(node->pn_atom);        JSString * s = ATOM_TO_STRING(node->pn_atom);
391        /* XXX - semantics changed in 1.7 */        /* XXX - semantics changed in 1.7 */
392        if (! ATOM_KEYWORD(node->pn_atom) && js_IsIdentifier(s)) {        if (! ATOM_KEYWORD(node->pn_atom) && js_IsIdentifier(s)) {
393          fputc('.', f);          Stream_write_char(f, '.');
394          print_string_atom(node->pn_atom, f);          print_string_atom(node->pn_atom, f);
395        }        }
396        else {        else {
397          fputc('[', f);          Stream_write_char(f, '[');
398          print_quoted_string_atom(node->pn_atom, f);          print_quoted_string_atom(node->pn_atom, f);
399          fputc(']', f);          Stream_write_char(f, ']');
400        }        }
401      }      }
402      break;      break;
403    case TOK_LB:    case TOK_LB:
404      instrument_expression(node->pn_left, f);      instrument_expression(node->pn_left, f);
405      fputc('[', f);      Stream_write_char(f, '[');
406      instrument_expression(node->pn_right, f);      instrument_expression(node->pn_right, f);
407      fputc(']', f);      Stream_write_char(f, ']');
408      break;      break;
409    case TOK_LP:    case TOK_LP:
410      instrument_function_call(node, f);      instrument_function_call(node, f);
411      break;      break;
412    case TOK_RB:    case TOK_RB:
413      fputc('[', f);      Stream_write_char(f, '[');
414      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) {
415        if (p != node->pn_head) {        if (p != node->pn_head) {
416          fprintf(f, ", ");          Stream_write_string(f, ", ");
417        }        }
418        /* TOK_COMMA is a special case: a hole in the array */        /* TOK_COMMA is a special case: a hole in the array */
419        if (p->pn_type != TOK_COMMA) {        if (p->pn_type != TOK_COMMA) {
# Line 421  Line 421 
421        }        }
422      }      }
423      if (node->pn_extra == PNX_ENDCOMMA) {      if (node->pn_extra == PNX_ENDCOMMA) {
424        fputc(',', f);        Stream_write_char(f, ',');
425      }      }
426      fputc(']', f);      Stream_write_char(f, ']');
427      break;      break;
428    case TOK_RC:    case TOK_RC:
429      fputc('{', f);      Stream_write_char(f, '{');
430      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) {
431        assert(p->pn_type == TOK_COLON);        assert(p->pn_type == TOK_COLON);
432        if (p != node->pn_head) {        if (p != node->pn_head) {
433          fprintf(f, ", ");          Stream_write_string(f, ", ");
434        }        }
435        instrument_expression(p->pn_left, f);        instrument_expression(p->pn_left, f);
436        fprintf(f, ": ");        Stream_write_string(f, ": ");
437        instrument_expression(p->pn_right, f);        instrument_expression(p->pn_right, f);
438      }      }
439      fputc('}', f);      Stream_write_char(f, '}');
440      break;      break;
441    case TOK_RP:    case TOK_RP:
442      fputc('(', f);      Stream_write_char(f, '(');
443      instrument_expression(node->pn_kid, f);      instrument_expression(node->pn_kid, f);
444      fputc(')', f);      Stream_write_char(f, ')');
445      break;      break;
446    case TOK_NAME:    case TOK_NAME:
447      print_string_atom(node->pn_atom, f);      print_string_atom(node->pn_atom, f);
# Line 477  Line 477 
477      To keep the output simple, special-case zero.      To keep the output simple, special-case zero.
478      */      */
479      if (node->pn_dval == 0.0) {      if (node->pn_dval == 0.0) {
480        fprintf(f, "0");        Stream_write_string(f, "0");
481      }      }
482      else {      else {
483        fprintf(f, "%.15g", node->pn_dval);        Stream_printf(f, "%.15g", node->pn_dval);
484      }      }
485      break;      break;
486    case TOK_PRIMARY:    case TOK_PRIMARY:
487      switch (node->pn_op) {      switch (node->pn_op) {
488      case JSOP_TRUE:      case JSOP_TRUE:
489        fprintf(f, "true");        Stream_write_string(f, "true");
490        break;        break;
491      case JSOP_FALSE:      case JSOP_FALSE:
492        fprintf(f, "false");        Stream_write_string(f, "false");
493        break;        break;
494      case JSOP_NULL:      case JSOP_NULL:
495        fprintf(f, "null");        Stream_write_string(f, "null");
496        break;        break;
497      case JSOP_THIS:      case JSOP_THIS:
498        fprintf(f, "this");        Stream_write_string(f, "this");
499        break;        break;
500      /* jsscan.h mentions `super' ??? */      /* jsscan.h mentions `super' ??? */
501      default:      default:
# Line 504  Line 504 
504      break;      break;
505    case TOK_INSTANCEOF:    case TOK_INSTANCEOF:
506      instrument_expression(node->pn_left, f);      instrument_expression(node->pn_left, f);
507      fprintf(f, " instanceof ");      Stream_write_string(f, " instanceof ");
508      instrument_expression(node->pn_right, f);      instrument_expression(node->pn_right, f);
509      break;      break;
510    case TOK_IN:    case TOK_IN:
511      instrument_expression(node->pn_left, f);      instrument_expression(node->pn_left, f);
512      fprintf(f, " in ");      Stream_write_string(f, " in ");
513      instrument_expression(node->pn_right, f);      instrument_expression(node->pn_right, f);
514      break;      break;
515    default:    default:
# Line 517  Line 517 
517    }    }
518  }  }
519    
520  static void instrument_var_statement(JSParseNode * node, FILE * f, int indent) {  static void instrument_var_statement(JSParseNode * node, Stream * f, int indent) {
521    assert(node->pn_arity == PN_LIST);    assert(node->pn_arity == PN_LIST);
522    fprintf(f, "%*s", indent, "");    Stream_printf(f, "%*s", indent, "");
523    fprintf(f, "var ");    Stream_write_string(f, "var ");
524    for (struct JSParseNode * p = node->pn_u.list.head; p != NULL; p = p->pn_next) {    for (struct JSParseNode * p = node->pn_u.list.head; p != NULL; p = p->pn_next) {
525      assert(p->pn_type == TOK_NAME);      assert(p->pn_type == TOK_NAME);
526      assert(p->pn_arity == PN_NAME);      assert(p->pn_arity == PN_NAME);
527      if (p != node->pn_head) {      if (p != node->pn_head) {
528        fprintf(f, ", ");        Stream_write_string(f, ", ");
529      }      }
530      print_string_atom(p->pn_atom, f);      print_string_atom(p->pn_atom, f);
531      if (p->pn_expr != NULL) {      if (p->pn_expr != NULL) {
532        fprintf(f, " = ");        Stream_write_string(f, " = ");
533        instrument_expression(p->pn_expr, f);        instrument_expression(p->pn_expr, f);
534      }      }
535    }    }
536  }  }
537    
538  static void output_statement(JSParseNode * node, FILE * f, int indent) {  static void output_statement(JSParseNode * node, Stream * f, int indent) {
539    switch (node->pn_type) {    switch (node->pn_type) {
540    case TOK_FUNCTION:    case TOK_FUNCTION:
541      instrument_function(node, f, indent);      instrument_function(node, f, indent);
# Line 543  Line 543 
543    case TOK_LC:    case TOK_LC:
544      assert(node->pn_arity == PN_LIST);      assert(node->pn_arity == PN_LIST);
545  /*  /*
546      fprintf(f, "{\n");      Stream_write_string(f, "{\n");
547  */  */
548      for (struct JSParseNode * p = node->pn_u.list.head; p != NULL; p = p->pn_next) {      for (struct JSParseNode * p = node->pn_u.list.head; p != NULL; p = p->pn_next) {
549        instrument_statement(p, f, indent);        instrument_statement(p, f, indent);
550      }      }
551  /*  /*
552      fprintf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
553      fprintf(f, "}\n");      Stream_write_string(f, "}\n");
554  */  */
555      break;      break;
556    case TOK_IF:    case TOK_IF:
557      assert(node->pn_arity == PN_TERNARY);      assert(node->pn_arity == PN_TERNARY);
558      fprintf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
559      fprintf(f, "if (");      Stream_write_string(f, "if (");
560      instrument_expression(node->pn_kid1, f);      instrument_expression(node->pn_kid1, f);
561      fprintf(f, ") {\n");      Stream_write_string(f, ") {\n");
562      instrument_statement(node->pn_kid2, f, indent + 2);      instrument_statement(node->pn_kid2, f, indent + 2);
563      fprintf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
564      fprintf(f, "}\n");      Stream_write_string(f, "}\n");
565      if (node->pn_kid3) {      if (node->pn_kid3) {
566        fprintf(f, "%*s", indent, "");        Stream_printf(f, "%*s", indent, "");
567        fprintf(f, "else {\n");        Stream_write_string(f, "else {\n");
568        instrument_statement(node->pn_kid3, f, indent + 2);        instrument_statement(node->pn_kid3, f, indent + 2);
569        fprintf(f, "%*s", indent, "");        Stream_printf(f, "%*s", indent, "");
570        fprintf(f, "}\n");        Stream_write_string(f, "}\n");
571      }      }
572      break;      break;
573    case TOK_SWITCH:    case TOK_SWITCH:
574      assert(node->pn_arity == PN_BINARY);      assert(node->pn_arity == PN_BINARY);
575      fprintf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
576      fprintf(f, "switch (");      Stream_write_string(f, "switch (");
577      instrument_expression(node->pn_left, f);      instrument_expression(node->pn_left, f);
578      fprintf(f, ") {\n");      Stream_write_string(f, ") {\n");
579      for (struct JSParseNode * p = node->pn_right->pn_head; p != NULL; p = p->pn_next) {      for (struct JSParseNode * p = node->pn_right->pn_head; p != NULL; p = p->pn_next) {
580        fprintf(f, "%*s", indent, "");        Stream_printf(f, "%*s", indent, "");
581        switch (p->pn_type) {        switch (p->pn_type) {
582        case TOK_CASE:        case TOK_CASE:
583          fprintf(f, "case ");          Stream_write_string(f, "case ");
584          instrument_expression(p->pn_left, f);          instrument_expression(p->pn_left, f);
585          fprintf(f, ":\n");          Stream_write_string(f, ":\n");
586          break;          break;
587        case TOK_DEFAULT:        case TOK_DEFAULT:
588          fprintf(f, "default:\n");          Stream_write_string(f, "default:\n");
589          break;          break;
590        default:        default:
591          abort();          abort();
# Line 593  Line 593 
593        }        }
594        instrument_statement(p->pn_right, f, indent + 2);        instrument_statement(p->pn_right, f, indent + 2);
595      }      }
596      fprintf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
597      fprintf(f, "}\n");      Stream_write_string(f, "}\n");
598      break;      break;
599    case TOK_CASE:    case TOK_CASE:
600    case TOK_DEFAULT:    case TOK_DEFAULT:
# Line 602  Line 602 
602      break;      break;
603    case TOK_WHILE:    case TOK_WHILE:
604      assert(node->pn_arity == PN_BINARY);      assert(node->pn_arity == PN_BINARY);
605      fprintf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
606      fprintf(f, "while (");      Stream_write_string(f, "while (");
607      instrument_expression(node->pn_left, f);      instrument_expression(node->pn_left, f);
608      fprintf(f, ") {\n");      Stream_write_string(f, ") {\n");
609      instrument_statement(node->pn_right, f, indent + 2);      instrument_statement(node->pn_right, f, indent + 2);
610      fprintf(f, "}\n");      Stream_write_string(f, "}\n");
611      break;      break;
612    case TOK_DO:    case TOK_DO:
613      assert(node->pn_arity == PN_BINARY);      assert(node->pn_arity == PN_BINARY);
614      fprintf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
615      fprintf(f, "do {\n");      Stream_write_string(f, "do {\n");
616      instrument_statement(node->pn_left, f, indent + 2);      instrument_statement(node->pn_left, f, indent + 2);
617      fprintf(f, "}\n");      Stream_write_string(f, "}\n");
618      fprintf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
619      fprintf(f, "while (");      Stream_write_string(f, "while (");
620      instrument_expression(node->pn_right, f);      instrument_expression(node->pn_right, f);
621      fprintf(f, ");\n");      Stream_write_string(f, ");\n");
622      break;      break;
623    case TOK_FOR:    case TOK_FOR:
624      assert(node->pn_arity == PN_BINARY);      assert(node->pn_arity == PN_BINARY);
625      fprintf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
626      fprintf(f, "for (");      Stream_write_string(f, "for (");
627      switch (node->pn_left->pn_type) {      switch (node->pn_left->pn_type) {
628      case TOK_IN:      case TOK_IN:
629        /* for/in */        /* for/in */
# Line 646  Line 646 
646          break;          break;
647  */  */
648        }        }
649        fprintf(f, " in ");        Stream_write_string(f, " in ");
650        instrument_expression(node->pn_left->pn_right, f);        instrument_expression(node->pn_left->pn_right, f);
651        break;        break;
652      case TOK_RESERVED:      case TOK_RESERVED:
# Line 660  Line 660 
660            instrument_expression(node->pn_left->pn_kid1, f);            instrument_expression(node->pn_left->pn_kid1, f);
661          }          }
662        }        }
663        fprintf(f, ";");        Stream_write_string(f, ";");
664        if (node->pn_left->pn_kid2) {        if (node->pn_left->pn_kid2) {
665          fputc(' ', f);          Stream_write_char(f, ' ');
666          instrument_expression(node->pn_left->pn_kid2, f);          instrument_expression(node->pn_left->pn_kid2, f);
667        }        }
668        fprintf(f, ";");        Stream_write_string(f, ";");
669        if (node->pn_left->pn_kid3) {        if (node->pn_left->pn_kid3) {
670          fputc(' ', f);          Stream_write_char(f, ' ');
671          instrument_expression(node->pn_left->pn_kid3, f);          instrument_expression(node->pn_left->pn_kid3, f);
672        }        }
673        break;        break;
# Line 675  Line 675 
675        abort();        abort();
676        break;        break;
677      }      }
678      fprintf(f, ") {\n");      Stream_write_string(f, ") {\n");
679      instrument_statement(node->pn_right, f, indent + 2);      instrument_statement(node->pn_right, f, indent + 2);
680      fprintf(f, "}\n");      Stream_write_string(f, "}\n");
681      break;      break;
682    case TOK_THROW:    case TOK_THROW:
683      assert(node->pn_arity == PN_UNARY);      assert(node->pn_arity == PN_UNARY);
684      fprintf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
685      fprintf(f, "throw ");      Stream_write_string(f, "throw ");
686      instrument_expression(node->pn_u.unary.kid, f);      instrument_expression(node->pn_u.unary.kid, f);
687      fprintf(f, ";\n");      Stream_write_string(f, ";\n");
688      break;      break;
689    case TOK_TRY:    case TOK_TRY:
690      fprintf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
691      fprintf(f, "try {\n");      Stream_write_string(f, "try {\n");
692      instrument_statement(node->pn_kid1, f, indent + 2);      instrument_statement(node->pn_kid1, f, indent + 2);
693      fprintf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
694      fprintf(f, "}\n");      Stream_write_string(f, "}\n");
695      {      {
696        for (JSParseNode * catch = node->pn_kid2; catch != NULL; catch = catch->pn_kid2) {        for (JSParseNode * catch = node->pn_kid2; catch != NULL; catch = catch->pn_kid2) {
697          assert(catch->pn_type == TOK_CATCH);          assert(catch->pn_type == TOK_CATCH);
698          fprintf(f, "%*s", indent, "");          Stream_printf(f, "%*s", indent, "");
699          fprintf(f, "catch (");          Stream_write_string(f, "catch (");
700          assert(catch->pn_kid1->pn_arity == PN_NAME);          assert(catch->pn_kid1->pn_arity == PN_NAME);
701          print_string_atom(catch->pn_kid1->pn_atom, f);          print_string_atom(catch->pn_kid1->pn_atom, f);
702          if (catch->pn_kid1->pn_expr) {          if (catch->pn_kid1->pn_expr) {
703            fprintf(f, " if ");            Stream_write_string(f, " if ");
704            instrument_expression(catch->pn_kid1->pn_expr, f);            instrument_expression(catch->pn_kid1->pn_expr, f);
705          }          }
706          fprintf(f, ") {\n");          Stream_write_string(f, ") {\n");
707          instrument_statement(catch->pn_kid3, f, indent + 2);          instrument_statement(catch->pn_kid3, f, indent + 2);
708          fprintf(f, "%*s", indent, "");          Stream_printf(f, "%*s", indent, "");
709          fprintf(f, "}\n");          Stream_write_string(f, "}\n");
710        }        }
711      }      }
712      if (node->pn_kid3) {      if (node->pn_kid3) {
713        fprintf(f, "%*s", indent, "");        Stream_printf(f, "%*s", indent, "");
714        fprintf(f, "finally {\n");        Stream_write_string(f, "finally {\n");
715        instrument_statement(node->pn_kid3, f, indent + 2);        instrument_statement(node->pn_kid3, f, indent + 2);
716        fprintf(f, "%*s", indent, "");        Stream_printf(f, "%*s", indent, "");
717        fprintf(f, "}\n");        Stream_write_string(f, "}\n");
718      }      }
719      break;      break;
720    case TOK_CATCH:    case TOK_CATCH:
# Line 723  Line 723 
723    case TOK_BREAK:    case TOK_BREAK:
724    case TOK_CONTINUE:    case TOK_CONTINUE:
725      assert(node->pn_arity == PN_NAME || node->pn_arity == PN_NULLARY);      assert(node->pn_arity == PN_NAME || node->pn_arity == PN_NULLARY);
726      fprintf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
727      fputs(node->pn_type == TOK_BREAK? "break": "continue", f);      Stream_write_string(f, node->pn_type == TOK_BREAK? "break": "continue");
728      JSAtom * atom = node->pn_u.name.atom;      JSAtom * atom = node->pn_u.name.atom;
729      if (atom != NULL) {      if (atom != NULL) {
730        fputc(' ', f);        Stream_write_char(f, ' ');
731        print_string_atom(node->pn_atom, f);        print_string_atom(node->pn_atom, f);
732      }      }
733      fprintf(f, ";\n");      Stream_write_string(f, ";\n");
734      break;      break;
735    case TOK_WITH:    case TOK_WITH:
736      assert(node->pn_arity == PN_BINARY);      assert(node->pn_arity == PN_BINARY);
737      fprintf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
738      fprintf(f, "with (");      Stream_write_string(f, "with (");
739      instrument_expression(node->pn_left, f);      instrument_expression(node->pn_left, f);
740      fprintf(f, ") {\n");      Stream_write_string(f, ") {\n");
741      instrument_statement(node->pn_right, f, indent + 2);      instrument_statement(node->pn_right, f, indent + 2);
742      fprintf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
743      fprintf(f, "}\n");      Stream_write_string(f, "}\n");
744      break;      break;
745    case TOK_VAR:    case TOK_VAR:
746      instrument_var_statement(node, f, indent);      instrument_var_statement(node, f, indent);
747      fprintf(f, ";\n");      Stream_write_string(f, ";\n");
748      break;      break;
749    case TOK_RETURN:    case TOK_RETURN:
750      assert(node->pn_arity == PN_UNARY);      assert(node->pn_arity == PN_UNARY);
751      fprintf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
752      fprintf(f, "return");      Stream_write_string(f, "return");
753      if (node->pn_kid != NULL) {      if (node->pn_kid != NULL) {
754        fprintf(f, " ");        Stream_write_char(f, ' ');
755        instrument_expression(node->pn_kid, f);        instrument_expression(node->pn_kid, f);
756      }      }
757      fprintf(f, ";\n");      Stream_write_string(f, ";\n");
758      break;      break;
759    case TOK_SEMI:    case TOK_SEMI:
760      assert(node->pn_arity == PN_UNARY);      assert(node->pn_arity == PN_UNARY);
761      fprintf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
762      if (node->pn_kid != NULL) {      if (node->pn_kid != NULL) {
763        instrument_expression(node->pn_kid, f);        instrument_expression(node->pn_kid, f);
764      }      }
765      fprintf(f, ";\n");      Stream_write_string(f, ";\n");
766      break;      break;
767    case TOK_COLON:    case TOK_COLON:
768      assert(node->pn_arity == PN_NAME);      assert(node->pn_arity == PN_NAME);
# Line 770  Line 770 
770      This one is tricky: can't output instrumentation between the label and the      This one is tricky: can't output instrumentation between the label and the
771      statement it's supposed to label ...      statement it's supposed to label ...
772      */      */
773      fprintf(f, "%*s", indent < 2? 0: indent - 2, "");      Stream_printf(f, "%*s", indent < 2? 0: indent - 2, "");
774      print_string_atom(node->pn_atom, f);      print_string_atom(node->pn_atom, f);
775      fprintf(f, ":\n");      Stream_write_string(f, ":\n");
776      /*      /*
777      ... use output_statement instead of instrument_statement.      ... use output_statement instead of instrument_statement.
778      */      */
# Line 788  Line 788 
788  TOK_FUNCTION is handled as a statement and as an expression.  TOK_FUNCTION is handled as a statement and as an expression.
789  TOK_EXPORT, TOK_IMPORT are not handled.  TOK_EXPORT, TOK_IMPORT are not handled.
790  */  */
791  static void instrument_statement(JSParseNode * node, FILE * f, int indent) {  static void instrument_statement(JSParseNode * node, Stream * f, int indent) {
792    if (node->pn_type != TOK_LC) {    if (node->pn_type != TOK_LC) {
793      int line = node->pn_pos.begin.lineno;      int line = node->pn_pos.begin.lineno;
794      /* the root node has line number 0 */      /* the root node has line number 0 */
795      if (line != 0) {      if (line != 0) {
796        fprintf(f, "%*s", indent, "");        Stream_printf(f, "%*s", indent, "");
797        fprintf(f, "_$jscoverage['%s'][%d]++;\n", file_id, line);        Stream_printf(f, "_$jscoverage['%s'][%d]++;\n", file_id, line);
798        lines[line - 1] = 1;        lines[line - 1] = 1;
799      }      }
800    }    }
801    output_statement(node, f, indent);    output_statement(node, f, indent);
802  }  }
803    
804  static void instrument_js_stream(const char * id, int line, FILE * input, FILE * output, const char * temporary_file_name) {  void jscoverage_instrument_js(const char * id, Stream * input, Stream * output) {
805    file_id = id;    file_id = id;
806    
807    /* scan the javascript */    /* scan the javascript */
808    JSTokenStream * token_stream = js_NewFileTokenStream(context, NULL, input);    size_t input_length = input->length;
809      jschar * base = js_InflateString(context, input->data, &input_length);
810      if (base == NULL) {
811        fatal("out of memory");
812      }
813      JSTokenStream * token_stream = js_NewTokenStream(context, base, input_length, NULL, 1, NULL);
814    if (token_stream == NULL) {    if (token_stream == NULL) {
815      fatal("cannot create token stream from file: %s", file_id);      fatal("cannot create token stream from file: %s", file_id);
816    }    }
# Line 822  Line 827 
827    }    }
828    
829    /*    /*
830    Create a temporary file - we can't write directly to the output because we    An instrumented JavaScript file has 3 sections:
831    need to know the line number info first.    1. initialization
832      2. instrumented source code
833      3. original source code (TODO)
834    */    */
   FILE * temporary = fopen(temporary_file_name, "w+");  
   if (temporary == NULL) {  
     fatal("cannot create temporary file for script: %s", file_id);  
   }  
835    
836    /* write instrumented javascript to the temporary */    Stream * instrumented = Stream_new(0);
837    instrument_statement(node, temporary, 0);    instrument_statement(node, instrumented, 0);
838    
839    /* write line number info to the output */    /* write line number info to the output */
840    fprintf(output, "/* automatically generated by JSCoverage - do not edit */\n");    Stream_write_string(output, "/* automatically generated by JSCoverage - do not edit */\n");
841    fprintf(output, "if (! top._$jscoverage) {\n  top._$jscoverage = {};\n}\n");    Stream_write_string(output, "if (! top._$jscoverage) {\n  top._$jscoverage = {};\n}\n");
842    fprintf(output, "var _$jscoverage = top._$jscoverage;\n");    Stream_write_string(output, "var _$jscoverage = top._$jscoverage;\n");
843    fprintf(output, "if (! _$jscoverage['%s']) {\n", file_id);    Stream_printf(output, "if (! _$jscoverage['%s']) {\n", file_id);
844    fprintf(output, "  _$jscoverage['%s'] = [];\n", file_id);    Stream_printf(output, "  _$jscoverage['%s'] = [];\n", file_id);
845    for (int i = 0; i < num_lines; i++) {    for (int i = 0; i < num_lines; i++) {
846      if (lines[i]) {      if (lines[i]) {
847        fprintf(output, "  _$jscoverage['%s'][%d] = 0;\n", file_id, i + 1);        Stream_printf(output, "  _$jscoverage['%s'][%d] = 0;\n", file_id, i + 1);
848      }      }
849    }    }
850    fprintf(output, "}\n");    Stream_write_string(output, "}\n");
851    free(lines);    free(lines);
852    lines = NULL;    lines = NULL;
853    
854    /* copy the temporary to the output */    /* copy the instrumented source code to the output */
855    fseek(temporary, 0, SEEK_SET);    Stream_write(output, instrumented->data, instrumented->length);
   copy_stream(temporary, output);  
856    
857    fclose(temporary);    Stream_delete(instrumented);
858    
859    file_id = NULL;    JS_free(context, base);
 }  
860    
861  void jscoverage_instrument_js(const char * id, FILE * input, FILE * output, const char * temporary_file_name) {    file_id = NULL;
   instrument_js_stream(id, 0, input, output, temporary_file_name);  
862  }  }

Legend:
Removed from v.90  
changed lines
  Added in v.92

  ViewVC Help
Powered by ViewVC 1.1.24