/[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 345 by siliconforks, Fri Oct 24 16:16:00 2008 UTC revision 378 by siliconforks, Tue Oct 28 05:31:03 2008 UTC
# Line 28  Line 28 
28  #include <jsapi.h>  #include <jsapi.h>
29  #include <jsarena.h>  #include <jsarena.h>
30  #include <jsatom.h>  #include <jsatom.h>
31    #include <jsemit.h>
32  #include <jsexn.h>  #include <jsexn.h>
33  #include <jsfun.h>  #include <jsfun.h>
34  #include <jsinterp.h>  #include <jsinterp.h>
# Line 51  Line 52 
52    struct IfDirective * next;    struct IfDirective * next;
53  };  };
54    
55    bool jscoverage_mozilla = false;
56    
57  static bool * exclusive_directives = NULL;  static bool * exclusive_directives = NULL;
58    
59  static JSRuntime * runtime = NULL;  static JSRuntime * runtime = NULL;
# Line 67  Line 70 
70  static uint16_t num_lines = 0;  static uint16_t num_lines = 0;
71    
72  void jscoverage_set_js_version(const char * version) {  void jscoverage_set_js_version(const char * version) {
73    js_version = atoi(version);    js_version = JS_StringToVersion(version);
74      if (js_version != JSVERSION_UNKNOWN) {
75        return;
76      }
77    
78      char * end;
79      js_version = (JSVersion) strtol(version, &end, 10);
80      if ((size_t) (end - version) != strlen(version)) {
81        fatal("invalid version: %s", version);
82      }
83  }  }
84    
85  void jscoverage_init(void) {  void jscoverage_init(void) {
# Line 264  Line 276 
276    FUNCTION_GETTER_OR_SETTER    FUNCTION_GETTER_OR_SETTER
277  };  };
278    
279    static void output_for_in(JSParseNode * node, Stream * f) {
280      assert(node->pn_type == TOK_FOR);
281      assert(node->pn_arity == PN_BINARY);
282      Stream_write_string(f, "for ");
283      if (node->pn_iflags & JSITER_FOREACH) {
284        Stream_write_string(f, "each ");
285      }
286      Stream_write_char(f, '(');
287      instrument_expression(node->pn_left, f);
288      Stream_write_char(f, ')');
289    }
290    
291    static void output_array_comprehension_or_generator_expression(JSParseNode * node, Stream * f) {
292      assert(node->pn_type == TOK_LEXICALSCOPE);
293      assert(node->pn_arity == PN_NAME);
294      JSParseNode * for_node = node->pn_expr;
295      assert(for_node->pn_type == TOK_FOR);
296      assert(for_node->pn_arity == PN_BINARY);
297      JSParseNode * p = for_node;
298      while (p->pn_type == TOK_FOR) {
299        p = p->pn_right;
300      }
301      JSParseNode * if_node = NULL;
302      if (p->pn_type == TOK_IF) {
303        if_node = p;
304        assert(if_node->pn_arity == PN_TERNARY);
305        p = if_node->pn_kid2;
306      }
307      assert(p->pn_arity == PN_UNARY);
308      p = p->pn_kid;
309      if (p->pn_type == TOK_YIELD) {
310        /* for generator expressions */
311        p = p->pn_kid;
312      }
313    
314      instrument_expression(p, f);
315      p = for_node;
316      while (p->pn_type == TOK_FOR) {
317        Stream_write_char(f, ' ');
318        output_for_in(p, f);
319        p = p->pn_right;
320      }
321      if (if_node) {
322        Stream_write_string(f, " if (");
323        instrument_expression(if_node->pn_kid1, f);
324        Stream_write_char(f, ')');
325      }
326    }
327    
328    static void output_destructuring_expression(JSParseNode * node, Stream * f) {
329      switch (node->pn_type) {
330      case TOK_NAME:
331        assert(node->pn_arity == PN_NAME);
332        print_string_atom(node->pn_atom, f);
333        if (node->pn_expr != NULL) {
334          Stream_write_string(f, " = ");
335          instrument_expression(node->pn_expr, f);
336        }
337        break;
338      case TOK_RB:
339        Stream_write_char(f, '[');
340        for (JSParseNode * p = node->pn_head; p != NULL; p = p->pn_next) {
341          if (p != node->pn_head) {
342            Stream_write_string(f, ", ");
343          }
344          /* TOK_COMMA is a special case: a hole in the array */
345          if (p->pn_type != TOK_COMMA) {
346            output_destructuring_expression(p, f);
347          }
348        }
349        if (node->pn_extra == PNX_ENDCOMMA) {
350          Stream_write_char(f, ',');
351        }
352        Stream_write_char(f, ']');
353        break;
354      case TOK_RC:
355        Stream_write_char(f, '{');
356        for (JSParseNode * p = node->pn_head; p != NULL; p = p->pn_next) {
357          if (p != node->pn_head) {
358            Stream_write_string(f, ", ");
359          }
360          if (p->pn_type != TOK_COLON) {
361            fatal_source(file_id, p->pn_pos.begin.lineno, "unsupported node type (%d)", p->pn_type);
362          }
363          instrument_expression(p->pn_left, f);
364          Stream_write_string(f, ": ");
365          output_destructuring_expression(p->pn_right, f);
366        }
367        Stream_write_char(f, '}');
368        break;
369      case TOK_ASSIGN:
370        output_destructuring_expression(node->pn_left, f);
371        Stream_write_string(f, " = ");
372        instrument_expression(node->pn_right, f);
373        break;
374      default:
375        fatal_source(file_id, node->pn_pos.begin.lineno, "unsupported node type (%d)", node->pn_type);
376        break;
377      }
378    }
379    
380  static void instrument_function(JSParseNode * node, Stream * f, int indent, enum FunctionType type) {  static void instrument_function(JSParseNode * node, Stream * f, int indent, enum FunctionType type) {
381    assert(node->pn_type == TOK_FUNCTION);    assert(node->pn_type == TOK_FUNCTION);
382    assert(node->pn_arity == PN_FUNC);    assert(node->pn_arity == PN_FUNC);
# Line 274  Line 387 
387    assert(object == &function->object);    assert(object == &function->object);
388    Stream_printf(f, "%*s", indent, "");    Stream_printf(f, "%*s", indent, "");
389    if (type == FUNCTION_NORMAL) {    if (type == FUNCTION_NORMAL) {
390      Stream_write_string(f, "function");      Stream_write_string(f, "function ");
391    }    }
392    
393    /* function name */    /* function name */
394    if (function->atom) {    if (function->atom) {
     Stream_write_char(f, ' ');  
395      print_string_atom(function->atom, f);      print_string_atom(function->atom, f);
396    }    }
397    
# Line 287  Line 399 
399    function parameters - see JS_DecompileFunction in jsapi.cpp, which calls    function parameters - see JS_DecompileFunction in jsapi.cpp, which calls
400    js_DecompileFunction in jsopcode.cpp    js_DecompileFunction in jsopcode.cpp
401    */    */
402    Stream_write_string(f, "(");    Stream_write_char(f, '(');
403    JSArenaPool pool;    JSArenaPool pool;
404    JS_INIT_ARENA_POOL(&pool, "instrument_function", 256, 1, &context->scriptStackQuota);    JS_INIT_ARENA_POOL(&pool, "instrument_function", 256, 1, &context->scriptStackQuota);
405    jsuword * local_names = NULL;    jsuword * local_names = NULL;
# Line 297  Line 409 
409        fatal("out of memory");        fatal("out of memory");
410      }      }
411    }    }
412      bool destructuring = false;
413    for (int i = 0; i < function->nargs; i++) {    for (int i = 0; i < function->nargs; i++) {
414      if (i > 0) {      if (i > 0) {
415        Stream_write_string(f, ", ");        Stream_write_string(f, ", ");
416      }      }
417      JSAtom * param = JS_LOCAL_NAME_TO_ATOM(local_names[i]);      JSAtom * param = JS_LOCAL_NAME_TO_ATOM(local_names[i]);
418      print_string_atom(param, f);      if (param == NULL) {
419          destructuring = true;
420          JSParseNode * expression = NULL;
421          assert(node->pn_body->pn_type == TOK_LC || node->pn_body->pn_type == TOK_BODY);
422          JSParseNode * semi = node->pn_body->pn_head;
423          assert(semi->pn_type == TOK_SEMI);
424          JSParseNode * comma = semi->pn_kid;
425          assert(comma->pn_type == TOK_COMMA);
426          for (JSParseNode * p = comma->pn_head; p != NULL; p = p->pn_next) {
427            assert(p->pn_type == TOK_ASSIGN);
428            JSParseNode * rhs = p->pn_right;
429            assert(JSSTRING_LENGTH(ATOM_TO_STRING(rhs->pn_atom)) == 0);
430            if (rhs->pn_slot == i) {
431              expression = p->pn_left;
432              break;
433            }
434          }
435          assert(expression != NULL);
436          output_destructuring_expression(expression, f);
437        }
438        else {
439          print_string_atom(param, f);
440        }
441    }    }
442    JS_FinishArenaPool(&pool);    JS_FinishArenaPool(&pool);
443    Stream_write_string(f, ") {\n");    Stream_write_string(f, ") {\n");
444    
445    /* function body */    /* function body */
446    if (function->flags & JSFUN_EXPR_CLOSURE) {    if (function->flags & JSFUN_EXPR_CLOSURE) {
447      /* expression closure */      /* expression closure - use output_statement instead of instrument_statement */
448      output_statement(node->pn_body, f, indent + 2, false);      if (node->pn_body->pn_type == TOK_BODY) {
449          assert(node->pn_body->pn_arity == PN_LIST);
450          assert(node->pn_body->pn_count == 2);
451          output_statement(node->pn_body->pn_head->pn_next, f, indent + 2, false);
452        }
453        else {
454          output_statement(node->pn_body, f, indent + 2, false);
455        }
456    }    }
457    else {    else {
458      instrument_statement(node->pn_body, f, indent + 2, false);      assert(node->pn_body->pn_type == TOK_LC);
459        assert(node->pn_body->pn_arity == PN_LIST);
460        JSParseNode * p = node->pn_body->pn_head;
461        if (destructuring) {
462          p = p->pn_next;
463        }
464        for (; p != NULL; p = p->pn_next) {
465          instrument_statement(p, f, indent + 2, false);
466        }
467    }    }
468    
469    Stream_write_string(f, "}\n");    Stream_write_string(f, "}\n");
470  }  }
471    
472  static void instrument_function_call(JSParseNode * node, Stream * f) {  static void instrument_function_call(JSParseNode * node, Stream * f) {
473    instrument_expression(node->pn_head, f);    JSParseNode * function_node = node->pn_head;
474      if (function_node->pn_type == TOK_FUNCTION) {
475        JSObject * object = function_node->pn_funpob->object;
476        assert(JS_ObjectIsFunction(context, object));
477        JSFunction * function = (JSFunction *) JS_GetPrivate(context, object);
478        assert(function);
479        assert(object == &function->object);
480    
481        if (function_node->pn_flags & TCF_GENEXP_LAMBDA) {
482          /* it's a generator expression */
483          Stream_write_char(f, '(');
484          output_array_comprehension_or_generator_expression(function_node->pn_body, f);
485          Stream_write_char(f, ')');
486          return;
487        }
488        else {
489          Stream_write_char(f, '(');
490          instrument_expression(function_node, f);
491          Stream_write_char(f, ')');
492        }
493      }
494      else {
495        instrument_expression(function_node, f);
496      }
497    Stream_write_char(f, '(');    Stream_write_char(f, '(');
498    for (struct JSParseNode * p = node->pn_head->pn_next; p != NULL; p = p->pn_next) {    for (struct JSParseNode * p = function_node->pn_next; p != NULL; p = p->pn_next) {
499      if (p != node->pn_head->pn_next) {      if (p != node->pn_head->pn_next) {
500        Stream_write_string(f, ", ");        Stream_write_string(f, ", ");
501      }      }
# Line 334  Line 507 
507  static void instrument_declarations(JSParseNode * list, Stream * f) {  static void instrument_declarations(JSParseNode * list, Stream * f) {
508    assert(list->pn_arity == PN_LIST);    assert(list->pn_arity == PN_LIST);
509    for (JSParseNode * p = list->pn_head; p != NULL; p = p->pn_next) {    for (JSParseNode * p = list->pn_head; p != NULL; p = p->pn_next) {
510      switch (p->pn_type) {      if (p != list->pn_head) {
511      case TOK_NAME:        Stream_write_string(f, ", ");
       assert(p->pn_arity == PN_NAME);  
       if (p != list->pn_head) {  
         Stream_write_string(f, ", ");  
       }  
       print_string_atom(p->pn_atom, f);  
       if (p->pn_expr != NULL) {  
         Stream_write_string(f, " = ");  
         instrument_expression(p->pn_expr, f);  
       }  
       break;  
     case TOK_ASSIGN:  
     case TOK_RB:  
     case TOK_RC:  
       /* destructuring */  
       instrument_expression(p, f);  
       break;  
     default:  
       abort();  
       break;  
512      }      }
513        output_destructuring_expression(p, f);
514    }    }
515  }  }
516    
 static void output_for_in(JSParseNode * node, Stream * f) {  
   assert(node->pn_type == TOK_FOR);  
   assert(node->pn_arity == PN_BINARY);  
   Stream_write_string(f, "for ");  
   if (node->pn_iflags & JSITER_FOREACH) {  
     Stream_write_string(f, "each ");  
   }  
   Stream_write_char(f, '(');  
   instrument_expression(node->pn_left, f);  
   Stream_write_char(f, ')');  
 }  
   
517  /*  /*
518  See <Expressions> in jsparse.h.  See <Expressions> in jsparse.h.
519  TOK_FUNCTION is handled as a statement and as an expression.  TOK_FUNCTION is handled as a statement and as an expression.
# Line 398  Line 541 
541      }      }
542      break;      break;
543    case TOK_ASSIGN:    case TOK_ASSIGN:
544      instrument_expression(node->pn_left, f);      switch (node->pn_left->pn_type) {
545        case TOK_RB:
546          output_destructuring_expression(node->pn_left, f);
547          break;
548        case TOK_RC:
549          Stream_write_char(f, '(');
550          output_destructuring_expression(node->pn_left, f);
551          Stream_write_char(f, ')');
552          break;
553        default:
554          instrument_expression(node->pn_left, f);
555          break;
556        }
557      Stream_write_char(f, ' ');      Stream_write_char(f, ' ');
558      switch (node->pn_op) {      switch (node->pn_op) {
559      case JSOP_ADD:      case JSOP_ADD:
# Line 485  Line 640 
640        instrument_expression(node->pn_kid, f);        instrument_expression(node->pn_kid, f);
641        break;        break;
642      default:      default:
643        abort();        fatal_source(file_id, node->pn_pos.begin.lineno, "unknown operator (%d)", node->pn_op);
644        break;        break;
645      }      }
646      break;      break;
# Line 533  Line 688 
688      instrument_expression(node->pn_kid, f);      instrument_expression(node->pn_kid, f);
689      break;      break;
690    case TOK_DOT:    case TOK_DOT:
691        /* numeric literals must be parenthesized */
692        switch (node->pn_expr->pn_type) {
693        case TOK_NUMBER:
694          Stream_write_char(f, '(');
695          instrument_expression(node->pn_expr, f);
696          Stream_write_char(f, ')');
697          break;
698        default:
699          instrument_expression(node->pn_expr, f);
700          break;
701        }
702      /*      /*
703      This may have originally been x['foo-bar'].  Because the string 'foo-bar'      This may have originally been x['foo-bar'].  Because the string 'foo-bar'
704      contains illegal characters, we have to use the subscript syntax instead of      contains illegal characters, we have to use the subscript syntax instead of
705      the dot syntax.      the dot syntax.
706      */      */
     instrument_expression(node->pn_expr, f);  
707      assert(ATOM_IS_STRING(node->pn_atom));      assert(ATOM_IS_STRING(node->pn_atom));
708      {      {
709        JSString * s = ATOM_TO_STRING(node->pn_atom);        JSString * s = ATOM_TO_STRING(node->pn_atom);
710        bool is_keyword = (js_CheckKeyword(JSSTRING_CHARS(s), JSSTRING_LENGTH(s)) != TOK_EOF);        bool must_quote;
711        if (! is_keyword && js_IsIdentifier(s)) {        if (JSSTRING_LENGTH(s) == 0) {
712          Stream_write_char(f, '.');          must_quote = true;
713          print_string_atom(node->pn_atom, f);        }
714          else if (js_CheckKeyword(JSSTRING_CHARS(s), JSSTRING_LENGTH(s)) != TOK_EOF) {
715            must_quote = true;
716          }
717          else if (! js_IsIdentifier(s)) {
718            must_quote = true;
719        }        }
720        else {        else {
721            must_quote = false;
722          }
723          if (must_quote) {
724          Stream_write_char(f, '[');          Stream_write_char(f, '[');
725          print_quoted_string_atom(node->pn_atom, f);          print_quoted_string_atom(node->pn_atom, f);
726          Stream_write_char(f, ']');          Stream_write_char(f, ']');
727        }        }
728          else {
729            Stream_write_char(f, '.');
730            print_string_atom(node->pn_atom, f);
731          }
732      }      }
733      break;      break;
734    case TOK_LB:    case TOK_LB:
# Line 580  Line 757 
757      Stream_write_char(f, ']');      Stream_write_char(f, ']');
758      break;      break;
759    case TOK_RC:    case TOK_RC:
760        Stream_write_char(f, '(');
761      Stream_write_char(f, '{');      Stream_write_char(f, '{');
762      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) {
763        assert(p->pn_type == TOK_COLON);        if (p->pn_type != TOK_COLON) {
764            fatal_source(file_id, p->pn_pos.begin.lineno, "unsupported node type (%d)", p->pn_type);
765          }
766        if (p != node->pn_head) {        if (p != node->pn_head) {
767          Stream_write_string(f, ", ");          Stream_write_string(f, ", ");
768        }        }
# Line 599  Line 779 
779          }          }
780          instrument_expression(p->pn_left, f);          instrument_expression(p->pn_left, f);
781          if (p->pn_right->pn_type != TOK_FUNCTION) {          if (p->pn_right->pn_type != TOK_FUNCTION) {
782            fatal("parse error: expected function");            fatal_source(file_id, p->pn_pos.begin.lineno, "expected function");
783          }          }
784          instrument_function(p->pn_right, f, 0, FUNCTION_GETTER_OR_SETTER);          instrument_function(p->pn_right, f, 0, FUNCTION_GETTER_OR_SETTER);
785          break;          break;
# Line 611  Line 791 
791        }        }
792      }      }
793      Stream_write_char(f, '}');      Stream_write_char(f, '}');
794        Stream_write_char(f, ')');
795      break;      break;
796    case TOK_RP:    case TOK_RP:
797      Stream_write_char(f, '(');      Stream_write_char(f, '(');
# Line 688  Line 869 
869      break;      break;
870    case TOK_YIELD:    case TOK_YIELD:
871      assert(node->pn_arity == PN_UNARY);      assert(node->pn_arity == PN_UNARY);
872      Stream_write_string(f, "yield ");      Stream_write_string(f, "yield");
873      instrument_expression(node->pn_kid, f);      if (node->pn_kid != NULL) {
874          Stream_write_char(f, ' ');
875          instrument_expression(node->pn_kid, f);
876        }
877      break;      break;
878    case TOK_ARRAYCOMP:    case TOK_ARRAYCOMP:
879      assert(node->pn_arity == PN_LIST);      assert(node->pn_arity == PN_LIST);
# Line 706  Line 890 
890          abort();          abort();
891          break;          break;
892        }        }
       assert(block_node->pn_type == TOK_LEXICALSCOPE);  
       assert(block_node->pn_arity == PN_NAME);  
       JSParseNode * for_node = block_node->pn_expr;  
       assert(for_node->pn_type == TOK_FOR);  
       assert(for_node->pn_arity == PN_BINARY);  
       JSParseNode * push_node;  
       JSParseNode * if_node = NULL;  
       switch (for_node->pn_right->pn_type) {  
       case TOK_ARRAYPUSH:  
         push_node = for_node->pn_right;  
         assert(push_node->pn_arity == PN_UNARY);  
         break;  
       case TOK_IF:  
         if_node = for_node->pn_right;  
         assert(if_node->pn_arity == PN_TERNARY);  
         push_node = if_node->pn_kid2;  
         break;  
       default:  
         abort();  
         break;  
       }  
893        Stream_write_char(f, '[');        Stream_write_char(f, '[');
894        instrument_expression(push_node->pn_kid, f);        output_array_comprehension_or_generator_expression(block_node, f);
       Stream_write_char(f, ' ');  
       output_for_in(for_node, f);  
       if (if_node) {  
         Stream_write_string(f, " if (");  
         instrument_expression(if_node->pn_kid1, f);  
         Stream_write_char(f, ')');  
       }  
895        Stream_write_char(f, ']');        Stream_write_char(f, ']');
896      }      }
897      break;      break;
# Line 750  Line 906 
906      instrument_declarations(node, f);      instrument_declarations(node, f);
907      break;      break;
908    default:    default:
909      fatal("unsupported node type in file %s: %d", file_id, node->pn_type);      fatal_source(file_id, node->pn_pos.begin.lineno, "unsupported node type (%d)", node->pn_type);
910    }    }
911  }  }
912    
# Line 779  Line 935 
935      uint16_t line = node->pn_pos.begin.lineno;      uint16_t line = node->pn_pos.begin.lineno;
936      if (! is_jscoverage_if) {      if (! is_jscoverage_if) {
937        if (line > num_lines) {        if (line > num_lines) {
938          fatal("%s: script contains more than 65,535 lines", file_id);          fatal("file %s contains more than 65,535 lines", file_id);
939        }        }
940        if (line >= 2 && exclusive_directives[line - 2]) {        if (line >= 2 && exclusive_directives[line - 2]) {
941          is_jscoverage_if = true;          is_jscoverage_if = true;
# Line 827  Line 983 
983      Stream_write_string(f, "switch (");      Stream_write_string(f, "switch (");
984      instrument_expression(node->pn_left, f);      instrument_expression(node->pn_left, f);
985      Stream_write_string(f, ") {\n");      Stream_write_string(f, ") {\n");
986      for (struct JSParseNode * p = node->pn_right->pn_head; p != NULL; p = p->pn_next) {      {
987        Stream_printf(f, "%*s", indent, "");        JSParseNode * list = node->pn_right;
988        switch (p->pn_type) {        if (list->pn_type == TOK_LEXICALSCOPE) {
989        case TOK_CASE:          list = list->pn_expr;
990          Stream_write_string(f, "case ");        }
991          instrument_expression(p->pn_left, f);        for (struct JSParseNode * p = list->pn_head; p != NULL; p = p->pn_next) {
992          Stream_write_string(f, ":\n");          Stream_printf(f, "%*s", indent, "");
993          break;          switch (p->pn_type) {
994        case TOK_DEFAULT:          case TOK_CASE:
995          Stream_write_string(f, "default:\n");            Stream_write_string(f, "case ");
996          break;            instrument_expression(p->pn_left, f);
997        default:            Stream_write_string(f, ":\n");
998          abort();            break;
999          break;          case TOK_DEFAULT:
1000              Stream_write_string(f, "default:\n");
1001              break;
1002            default:
1003              abort();
1004              break;
1005            }
1006            instrument_statement(p->pn_right, f, indent + 2, false);
1007        }        }
       instrument_statement(p->pn_right, f, indent + 2, false);  
1008      }      }
1009      Stream_printf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
1010      Stream_write_string(f, "}\n");      Stream_write_string(f, "}\n");
# Line 928  Line 1090 
1090          assert(catch->pn_type == TOK_CATCH);          assert(catch->pn_type == TOK_CATCH);
1091          Stream_printf(f, "%*s", indent, "");          Stream_printf(f, "%*s", indent, "");
1092          Stream_write_string(f, "catch (");          Stream_write_string(f, "catch (");
1093          /* this may not be a name - destructuring assignment */          output_destructuring_expression(catch->pn_kid1, f);
         /*  
         assert(catch->pn_kid1->pn_arity == PN_NAME);  
         print_string_atom(catch->pn_kid1->pn_atom, f);  
         */  
         instrument_expression(catch->pn_kid1, f);  
1094          if (catch->pn_kid2) {          if (catch->pn_kid2) {
1095            Stream_write_string(f, " if ");            Stream_write_string(f, " if ");
1096            instrument_expression(catch->pn_kid2, f);            instrument_expression(catch->pn_kid2, f);
# Line 1001  Line 1158 
1158      Stream_write_string(f, ";\n");      Stream_write_string(f, ";\n");
1159      break;      break;
1160    case TOK_COLON:    case TOK_COLON:
1161      {
1162      assert(node->pn_arity == PN_NAME);      assert(node->pn_arity == PN_NAME);
     /*  
     This one is tricky: can't output instrumentation between the label and the  
     statement it's supposed to label ...  
     */  
1163      Stream_printf(f, "%*s", indent < 2? 0: indent - 2, "");      Stream_printf(f, "%*s", indent < 2? 0: indent - 2, "");
1164      print_string_atom(node->pn_atom, f);      print_string_atom(node->pn_atom, f);
1165      Stream_write_string(f, ":\n");      Stream_write_string(f, ":\n");
1166      /*      JSParseNode * labelled = node->pn_expr;
1167      ... use output_statement instead of instrument_statement.      if (labelled->pn_type == TOK_LEXICALSCOPE) {
1168      */        labelled = labelled->pn_expr;
1169      output_statement(node->pn_expr, f, indent, false);      }
1170        if (labelled->pn_type == TOK_LC) {
1171          /* labelled block */
1172          Stream_printf(f, "%*s", indent, "");
1173          Stream_write_string(f, "{\n");
1174          instrument_statement(labelled, f, indent + 2, false);
1175          Stream_printf(f, "%*s", indent, "");
1176          Stream_write_string(f, "}\n");
1177        }
1178        else {
1179          /*
1180          This one is tricky: can't output instrumentation between the label and the
1181          statement it's supposed to label, so use output_statement instead of
1182          instrument_statement.
1183          */
1184          output_statement(labelled, f, indent, false);
1185        }
1186      break;      break;
1187      }
1188    case TOK_LEXICALSCOPE:    case TOK_LEXICALSCOPE:
1189      /* let statement */      /* let statement */
1190      assert(node->pn_arity == PN_NAME);      assert(node->pn_arity == PN_NAME);
# Line 1064  Line 1235 
1235        break;        break;
1236      }      }
1237      break;      break;
1238      case TOK_DEBUGGER:
1239        Stream_printf(f, "%*s", indent, "");
1240        Stream_write_string(f, "debugger;\n");
1241        break;
1242    default:    default:
1243      fatal("unsupported node type in file %s: %d", file_id, node->pn_type);      fatal_source(file_id, node->pn_pos.begin.lineno, "unsupported node type (%d)", node->pn_type);
1244    }    }
1245  }  }
1246    
# Line 1078  Line 1253 
1253    if (node->pn_type != TOK_LC && node->pn_type != TOK_LEXICALSCOPE) {    if (node->pn_type != TOK_LC && node->pn_type != TOK_LEXICALSCOPE) {
1254      uint16_t line = node->pn_pos.begin.lineno;      uint16_t line = node->pn_pos.begin.lineno;
1255      if (line > num_lines) {      if (line > num_lines) {
1256        fatal("%s: script contains more than 65,535 lines", file_id);        fatal("file %s contains more than 65,535 lines", file_id);
1257      }      }
1258    
1259      /* the root node has line number 0 */      /* the root node has line number 0 */
# Line 1126  Line 1301 
1301  }  }
1302    
1303  static void error_reporter(JSContext * context, const char * message, JSErrorReport * report) {  static void error_reporter(JSContext * context, const char * message, JSErrorReport * report) {
1304    fprintf(stderr, "jscoverage: parse error: line %u: %s\n", report->lineno, message);    warn_source(file_id, report->lineno, "%s", message);
1305  }  }
1306    
1307  void jscoverage_instrument_js(const char * id, const uint16_t * characters, size_t num_characters, Stream * output) {  void jscoverage_instrument_js(const char * id, const uint16_t * characters, size_t num_characters, Stream * output) {
# Line 1135  Line 1310 
1310    /* parse the javascript */    /* parse the javascript */
1311    JSParseContext parse_context;    JSParseContext parse_context;
1312    if (! js_InitParseContext(context, &parse_context, NULL, NULL, characters, num_characters, NULL, NULL, 1)) {    if (! js_InitParseContext(context, &parse_context, NULL, NULL, characters, num_characters, NULL, NULL, 1)) {
1313      fatal("cannot create token stream from file: %s", file_id);      fatal("cannot create token stream from file %s", file_id);
1314    }    }
1315    JSErrorReporter old_error_reporter = JS_SetErrorReporter(context, error_reporter);    JSErrorReporter old_error_reporter = JS_SetErrorReporter(context, error_reporter);
1316    JSParseNode * node = js_ParseScript(context, global, &parse_context);    JSParseNode * node = js_ParseScript(context, global, &parse_context);
1317    if (node == NULL) {    if (node == NULL) {
1318      js_ReportUncaughtException(context);      js_ReportUncaughtException(context);
1319      fatal("parse error in file: %s", file_id);      fatal("parse error in file %s", file_id);
1320    }    }
1321    JS_SetErrorReporter(context, old_error_reporter);    JS_SetErrorReporter(context, old_error_reporter);
1322    num_lines = node->pn_pos.end.lineno;    num_lines = node->pn_pos.end.lineno;
# Line 1162  Line 1337 
1337    size_t i = 0;    size_t i = 0;
1338    while (i < num_characters) {    while (i < num_characters) {
1339      if (line_number == UINT16_MAX) {      if (line_number == UINT16_MAX) {
1340        fatal("%s: script has more than 65,535 lines", file_id);        fatal("file %s contains more than 65,535 lines", file_id);
1341      }      }
1342      line_number++;      line_number++;
1343      size_t line_start = i;      size_t line_start = i;
# Line 1229  Line 1404 
1404    
1405    /* write line number info to the output */    /* write line number info to the output */
1406    Stream_write_string(output, "/* automatically generated by JSCoverage - do not edit */\n");    Stream_write_string(output, "/* automatically generated by JSCoverage - do not edit */\n");
1407    Stream_write_string(output, "if (! top._$jscoverage) {\n  top._$jscoverage = {};\n}\n");    if (jscoverage_mozilla) {
1408    Stream_write_string(output, "var _$jscoverage = top._$jscoverage;\n");      Stream_write_string(output, "try {\n");
1409        Stream_write_string(output, "  Components.utils.import('resource://gre/modules/jscoverage.jsm');\n");
1410        Stream_printf(output, "  dump('%s: successfully imported jscoverage module\\n');\n", id);
1411        Stream_write_string(output, "}\n");
1412        Stream_write_string(output, "catch (e) {\n");
1413        Stream_write_string(output, "  _$jscoverage = {};\n");
1414        Stream_printf(output, "  dump('%s: failed to import jscoverage module - coverage not available for this file\\n');\n", id);
1415        Stream_write_string(output, "}\n");
1416      }
1417      else {
1418        Stream_write_string(output, "if (! top._$jscoverage) {\n  top._$jscoverage = {};\n}\n");
1419        Stream_write_string(output, "var _$jscoverage = top._$jscoverage;\n");
1420      }
1421    Stream_printf(output, "if (! _$jscoverage['%s']) {\n", file_id);    Stream_printf(output, "if (! _$jscoverage['%s']) {\n", file_id);
1422    Stream_printf(output, "  _$jscoverage['%s'] = [];\n", file_id);    Stream_printf(output, "  _$jscoverage['%s'] = [];\n", file_id);
1423    for (int i = 0; i < num_lines; i++) {    for (int i = 0; i < num_lines; i++) {

Legend:
Removed from v.345  
changed lines
  Added in v.378

  ViewVC Help
Powered by ViewVC 1.1.24