/[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 341 by siliconforks, Fri Oct 24 16:14:43 2008 UTC revision 376 by siliconforks, Tue Oct 28 05:30:23 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 257  Line 269 
269    
270  static void instrument_expression(JSParseNode * node, Stream * f);  static void instrument_expression(JSParseNode * node, Stream * f);
271  static void instrument_statement(JSParseNode * node, Stream * f, int indent, bool is_jscoverage_if);  static void instrument_statement(JSParseNode * node, Stream * f, int indent, bool is_jscoverage_if);
272    static void output_statement(JSParseNode * node, Stream * f, int indent, bool is_jscoverage_if);
273    
274  enum FunctionType {  enum FunctionType {
275    FUNCTION_NORMAL,    FUNCTION_NORMAL,
276    FUNCTION_GETTER_OR_SETTER    FUNCTION_GETTER_OR_SETTER
277  };  };
278    
279    static void output_for_in(JSParseNode * node, Stream * f) {
280      assert(node->pn_type == TOK_FOR);
281      assert(node->pn_arity == PN_BINARY);
282      Stream_write_string(f, "for ");
283      if (node->pn_iflags & JSITER_FOREACH) {
284        Stream_write_string(f, "each ");
285      }
286      Stream_write_char(f, '(');
287      instrument_expression(node->pn_left, f);
288      Stream_write_char(f, ')');
289    }
290    
291    static void output_array_comprehension_or_generator_expression(JSParseNode * node, Stream * f) {
292      assert(node->pn_type == TOK_LEXICALSCOPE);
293      assert(node->pn_arity == PN_NAME);
294      JSParseNode * for_node = node->pn_expr;
295      assert(for_node->pn_type == TOK_FOR);
296      assert(for_node->pn_arity == PN_BINARY);
297      JSParseNode * p = for_node;
298      while (p->pn_type == TOK_FOR) {
299        p = p->pn_right;
300      }
301      JSParseNode * if_node = NULL;
302      if (p->pn_type == TOK_IF) {
303        if_node = p;
304        assert(if_node->pn_arity == PN_TERNARY);
305        p = if_node->pn_kid2;
306      }
307      assert(p->pn_arity == PN_UNARY);
308      p = p->pn_kid;
309      if (p->pn_type == TOK_YIELD) {
310        /* for generator expressions */
311        p = p->pn_kid;
312      }
313    
314      instrument_expression(p, f);
315      p = for_node;
316      while (p->pn_type == TOK_FOR) {
317        Stream_write_char(f, ' ');
318        output_for_in(p, f);
319        p = p->pn_right;
320      }
321      if (if_node) {
322        Stream_write_string(f, " if (");
323        instrument_expression(if_node->pn_kid1, f);
324        Stream_write_char(f, ')');
325      }
326    }
327    
328  static void instrument_function(JSParseNode * node, Stream * f, int indent, enum FunctionType type) {  static void instrument_function(JSParseNode * node, Stream * f, int indent, enum FunctionType type) {
329    assert(node->pn_type == TOK_FUNCTION);    assert(node->pn_type == TOK_FUNCTION);
330    assert(node->pn_arity == PN_FUNC);    assert(node->pn_arity == PN_FUNC);
# Line 273  Line 335 
335    assert(object == &function->object);    assert(object == &function->object);
336    Stream_printf(f, "%*s", indent, "");    Stream_printf(f, "%*s", indent, "");
337    if (type == FUNCTION_NORMAL) {    if (type == FUNCTION_NORMAL) {
338      Stream_write_string(f, "function");      Stream_write_string(f, "function ");
339    }    }
340    
341    /* function name */    /* function name */
342    if (function->atom) {    if (function->atom) {
     Stream_write_char(f, ' ');  
343      print_string_atom(function->atom, f);      print_string_atom(function->atom, f);
344    }    }
345    
# Line 286  Line 347 
347    function parameters - see JS_DecompileFunction in jsapi.cpp, which calls    function parameters - see JS_DecompileFunction in jsapi.cpp, which calls
348    js_DecompileFunction in jsopcode.cpp    js_DecompileFunction in jsopcode.cpp
349    */    */
350    Stream_write_string(f, "(");    Stream_write_char(f, '(');
351    JSArenaPool pool;    JSArenaPool pool;
352    JS_INIT_ARENA_POOL(&pool, "instrument_function", 256, 1, &context->scriptStackQuota);    JS_INIT_ARENA_POOL(&pool, "instrument_function", 256, 1, &context->scriptStackQuota);
353    jsuword * local_names = NULL;    jsuword * local_names = NULL;
# Line 296  Line 357 
357        fatal("out of memory");        fatal("out of memory");
358      }      }
359    }    }
360      bool destructuring = false;
361    for (int i = 0; i < function->nargs; i++) {    for (int i = 0; i < function->nargs; i++) {
362      if (i > 0) {      if (i > 0) {
363        Stream_write_string(f, ", ");        Stream_write_string(f, ", ");
364      }      }
365      JSAtom * param = JS_LOCAL_NAME_TO_ATOM(local_names[i]);      JSAtom * param = JS_LOCAL_NAME_TO_ATOM(local_names[i]);
366      print_string_atom(param, f);      if (param == NULL) {
367          destructuring = true;
368          JSParseNode * expression = NULL;
369          assert(node->pn_body->pn_type == TOK_LC || node->pn_body->pn_type == TOK_BODY);
370          JSParseNode * semi = node->pn_body->pn_head;
371          assert(semi->pn_type == TOK_SEMI);
372          JSParseNode * comma = semi->pn_kid;
373          assert(comma->pn_type == TOK_COMMA);
374          for (JSParseNode * p = comma->pn_head; p != NULL; p = p->pn_next) {
375            assert(p->pn_type == TOK_ASSIGN);
376            JSParseNode * rhs = p->pn_right;
377            assert(JSSTRING_LENGTH(ATOM_TO_STRING(rhs->pn_atom)) == 0);
378            if (rhs->pn_slot == i) {
379              expression = p->pn_left;
380              break;
381            }
382          }
383          assert(expression != NULL);
384          instrument_expression(expression, f);
385        }
386        else {
387          print_string_atom(param, f);
388        }
389    }    }
390    JS_FinishArenaPool(&pool);    JS_FinishArenaPool(&pool);
391    Stream_write_string(f, ") {\n");    Stream_write_string(f, ") {\n");
392    
393    /* function body */    /* function body */
394    instrument_statement(node->pn_body, f, indent + 2, false);    if (function->flags & JSFUN_EXPR_CLOSURE) {
395        /* expression closure - use output_statement instead of instrument_statement */
396        if (node->pn_body->pn_type == TOK_BODY) {
397          assert(node->pn_body->pn_arity == PN_LIST);
398          assert(node->pn_body->pn_count == 2);
399          output_statement(node->pn_body->pn_head->pn_next, f, indent + 2, false);
400        }
401        else {
402          output_statement(node->pn_body, f, indent + 2, false);
403        }
404      }
405      else {
406        assert(node->pn_body->pn_type == TOK_LC);
407        assert(node->pn_body->pn_arity == PN_LIST);
408        JSParseNode * p = node->pn_body->pn_head;
409        if (destructuring) {
410          p = p->pn_next;
411        }
412        for (; p != NULL; p = p->pn_next) {
413          instrument_statement(p, f, indent + 2, false);
414        }
415      }
416    
417    Stream_write_string(f, "}\n");    Stream_write_string(f, "}\n");
418  }  }
419    
420  static void instrument_function_call(JSParseNode * node, Stream * f) {  static void instrument_function_call(JSParseNode * node, Stream * f) {
421    instrument_expression(node->pn_head, f);    JSParseNode * function_node = node->pn_head;
422      if (function_node->pn_type == TOK_FUNCTION) {
423        JSObject * object = function_node->pn_funpob->object;
424        assert(JS_ObjectIsFunction(context, object));
425        JSFunction * function = (JSFunction *) JS_GetPrivate(context, object);
426        assert(function);
427        assert(object == &function->object);
428    
429        if (function_node->pn_flags & TCF_GENEXP_LAMBDA) {
430          /* it's a generator expression */
431          Stream_write_char(f, '(');
432          output_array_comprehension_or_generator_expression(function_node->pn_body, f);
433          Stream_write_char(f, ')');
434          return;
435        }
436        else {
437          Stream_write_char(f, '(');
438          instrument_expression(function_node, f);
439          Stream_write_char(f, ')');
440        }
441      }
442      else {
443        instrument_expression(function_node, f);
444      }
445    Stream_write_char(f, '(');    Stream_write_char(f, '(');
446    for (struct JSParseNode * p = node->pn_head->pn_next; p != NULL; p = p->pn_next) {    for (struct JSParseNode * p = function_node->pn_next; p != NULL; p = p->pn_next) {
447      if (p != node->pn_head->pn_next) {      if (p != node->pn_head->pn_next) {
448        Stream_write_string(f, ", ");        Stream_write_string(f, ", ");
449      }      }
# Line 340  Line 468 
468        }        }
469        break;        break;
470      case TOK_ASSIGN:      case TOK_ASSIGN:
471          /* destructuring */
472          instrument_expression(p->pn_left, f);
473          Stream_write_string(f, " = ");
474          instrument_expression(p->pn_right, f);
475          break;
476      case TOK_RB:      case TOK_RB:
477      case TOK_RC:      case TOK_RC:
478        /* destructuring */        /* destructuring */
# Line 379  Line 512 
512      }      }
513      break;      break;
514    case TOK_ASSIGN:    case TOK_ASSIGN:
515      instrument_expression(node->pn_left, f);      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      Stream_write_char(f, ' ');      Stream_write_char(f, ' ');
525      switch (node->pn_op) {      switch (node->pn_op) {
526      case JSOP_ADD:      case JSOP_ADD:
# Line 466  Line 607 
607        instrument_expression(node->pn_kid, f);        instrument_expression(node->pn_kid, f);
608        break;        break;
609      default:      default:
610        abort();        fatal_source(file_id, node->pn_pos.begin.lineno, "unknown operator (%d)", node->pn_op);
611        break;        break;
612      }      }
613      break;      break;
# Line 514  Line 655 
655      instrument_expression(node->pn_kid, f);      instrument_expression(node->pn_kid, f);
656      break;      break;
657    case TOK_DOT:    case TOK_DOT:
658        /* numeric literals must be parenthesized */
659        if (node->pn_expr->pn_type == TOK_NUMBER) {
660          Stream_write_char(f, '(');
661          instrument_expression(node->pn_expr, f);
662          Stream_write_char(f, ')');
663        }
664        else {
665          instrument_expression(node->pn_expr, f);
666        }
667      /*      /*
668      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'
669      contains illegal characters, we have to use the subscript syntax instead of      contains illegal characters, we have to use the subscript syntax instead of
670      the dot syntax.      the dot syntax.
671      */      */
     instrument_expression(node->pn_expr, f);  
672      assert(ATOM_IS_STRING(node->pn_atom));      assert(ATOM_IS_STRING(node->pn_atom));
673      {      {
674        JSString * s = ATOM_TO_STRING(node->pn_atom);        JSString * s = ATOM_TO_STRING(node->pn_atom);
675        bool is_keyword = (js_CheckKeyword(JSSTRING_CHARS(s), JSSTRING_LENGTH(s)) != TOK_EOF);        bool must_quote;
676        if (! is_keyword && js_IsIdentifier(s)) {        if (JSSTRING_LENGTH(s) == 0) {
677          Stream_write_char(f, '.');          must_quote = true;
678          print_string_atom(node->pn_atom, f);        }
679          else if (js_CheckKeyword(JSSTRING_CHARS(s), JSSTRING_LENGTH(s)) != TOK_EOF) {
680            must_quote = true;
681          }
682          else if (! js_IsIdentifier(s)) {
683            must_quote = true;
684        }        }
685        else {        else {
686            must_quote = false;
687          }
688          if (must_quote) {
689          Stream_write_char(f, '[');          Stream_write_char(f, '[');
690          print_quoted_string_atom(node->pn_atom, f);          print_quoted_string_atom(node->pn_atom, f);
691          Stream_write_char(f, ']');          Stream_write_char(f, ']');
692        }        }
693          else {
694            Stream_write_char(f, '.');
695            print_string_atom(node->pn_atom, f);
696          }
697      }      }
698      break;      break;
699    case TOK_LB:    case TOK_LB:
# Line 563  Line 724 
724    case TOK_RC:    case TOK_RC:
725      Stream_write_char(f, '{');      Stream_write_char(f, '{');
726      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) {
727        assert(p->pn_type == TOK_COLON);        if (p->pn_type != TOK_COLON) {
728            fatal_source(file_id, p->pn_pos.begin.lineno, "unsupported node type (%d)", p->pn_type);
729          }
730        if (p != node->pn_head) {        if (p != node->pn_head) {
731          Stream_write_string(f, ", ");          Stream_write_string(f, ", ");
732        }        }
# Line 580  Line 743 
743          }          }
744          instrument_expression(p->pn_left, f);          instrument_expression(p->pn_left, f);
745          if (p->pn_right->pn_type != TOK_FUNCTION) {          if (p->pn_right->pn_type != TOK_FUNCTION) {
746            fatal("parse error: expected function");            fatal_source(file_id, p->pn_pos.begin.lineno, "expected function");
747          }          }
748          instrument_function(p->pn_right, f, 0, FUNCTION_GETTER_OR_SETTER);          instrument_function(p->pn_right, f, 0, FUNCTION_GETTER_OR_SETTER);
749          break;          break;
# Line 667  Line 830 
830      Stream_write_string(f, ") ");      Stream_write_string(f, ") ");
831      instrument_expression(node->pn_expr->pn_right, f);      instrument_expression(node->pn_expr->pn_right, f);
832      break;      break;
833      case TOK_YIELD:
834        assert(node->pn_arity == PN_UNARY);
835        Stream_write_string(f, "yield");
836        if (node->pn_kid != NULL) {
837          Stream_write_char(f, ' ');
838          instrument_expression(node->pn_kid, f);
839        }
840        break;
841      case TOK_ARRAYCOMP:
842        assert(node->pn_arity == PN_LIST);
843        {
844          JSParseNode * block_node;
845          switch (node->pn_count) {
846          case 1:
847            block_node = node->pn_head;
848            break;
849          case 2:
850            block_node = node->pn_head->pn_next;
851            break;
852          default:
853            abort();
854            break;
855          }
856          Stream_write_char(f, '[');
857          output_array_comprehension_or_generator_expression(block_node, f);
858          Stream_write_char(f, ']');
859        }
860        break;
861      case TOK_VAR:
862        assert(node->pn_arity == PN_LIST);
863        Stream_write_string(f, "var ");
864        instrument_declarations(node, f);
865        break;
866      case TOK_LET:
867        assert(node->pn_arity == PN_LIST);
868        Stream_write_string(f, "let ");
869        instrument_declarations(node, f);
870        break;
871    default:    default:
872      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);
873    }    }
874  }  }
875    
 static void instrument_var_statement(JSParseNode * node, Stream * f, int indent) {  
   assert(node->pn_arity == PN_LIST);  
   Stream_printf(f, "%*s", indent, "");  
   Stream_write_string(f, "var ");  
   instrument_declarations(node, f);  
 }  
   
 static void instrument_let_definition(JSParseNode * node, Stream * f, int indent) {  
   assert(node->pn_arity == PN_LIST);  
   Stream_printf(f, "%*s", indent, "");  
   Stream_write_string(f, "let ");  
   instrument_declarations(node, f);  
 }  
   
876  static void output_statement(JSParseNode * node, Stream * f, int indent, bool is_jscoverage_if) {  static void output_statement(JSParseNode * node, Stream * f, int indent, bool is_jscoverage_if) {
877    switch (node->pn_type) {    switch (node->pn_type) {
878    case TOK_FUNCTION:    case TOK_FUNCTION:
# Line 711  Line 898 
898      uint16_t line = node->pn_pos.begin.lineno;      uint16_t line = node->pn_pos.begin.lineno;
899      if (! is_jscoverage_if) {      if (! is_jscoverage_if) {
900        if (line > num_lines) {        if (line > num_lines) {
901          fatal("%s: script contains more than 65,535 lines", file_id);          fatal("file %s contains more than 65,535 lines", file_id);
902        }        }
903        if (line >= 2 && exclusive_directives[line - 2]) {        if (line >= 2 && exclusive_directives[line - 2]) {
904          is_jscoverage_if = true;          is_jscoverage_if = true;
# Line 759  Line 946 
946      Stream_write_string(f, "switch (");      Stream_write_string(f, "switch (");
947      instrument_expression(node->pn_left, f);      instrument_expression(node->pn_left, f);
948      Stream_write_string(f, ") {\n");      Stream_write_string(f, ") {\n");
949      for (struct JSParseNode * p = node->pn_right->pn_head; p != NULL; p = p->pn_next) {      {
950        Stream_printf(f, "%*s", indent, "");        JSParseNode * list = node->pn_right;
951        switch (p->pn_type) {        if (list->pn_type == TOK_LEXICALSCOPE) {
952        case TOK_CASE:          list = list->pn_expr;
953          Stream_write_string(f, "case ");        }
954          instrument_expression(p->pn_left, f);        for (struct JSParseNode * p = list->pn_head; p != NULL; p = p->pn_next) {
955          Stream_write_string(f, ":\n");          Stream_printf(f, "%*s", indent, "");
956          break;          switch (p->pn_type) {
957        case TOK_DEFAULT:          case TOK_CASE:
958          Stream_write_string(f, "default:\n");            Stream_write_string(f, "case ");
959          break;            instrument_expression(p->pn_left, f);
960        default:            Stream_write_string(f, ":\n");
961          abort();            break;
962          break;          case TOK_DEFAULT:
963              Stream_write_string(f, "default:\n");
964              break;
965            default:
966              abort();
967              break;
968            }
969            instrument_statement(p->pn_right, f, indent + 2, false);
970        }        }
       instrument_statement(p->pn_right, f, indent + 2, false);  
971      }      }
972      Stream_printf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
973      Stream_write_string(f, "}\n");      Stream_write_string(f, "}\n");
# Line 806  Line 999 
999    case TOK_FOR:    case TOK_FOR:
1000      assert(node->pn_arity == PN_BINARY);      assert(node->pn_arity == PN_BINARY);
1001      Stream_printf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
     Stream_write_string(f, "for ");  
     if (node->pn_iflags & JSITER_FOREACH) {  
       Stream_write_string(f, "each ");  
     }  
     Stream_write_char(f, '(');  
1002      switch (node->pn_left->pn_type) {      switch (node->pn_left->pn_type) {
1003      case TOK_IN:      case TOK_IN:
1004        /* for/in */        /* for/in */
1005        assert(node->pn_left->pn_arity == PN_BINARY);        assert(node->pn_left->pn_arity == PN_BINARY);
1006        switch (node->pn_left->pn_left->pn_type) {        output_for_in(node, f);
       case TOK_VAR:  
         instrument_var_statement(node->pn_left->pn_left, f, 0);  
         break;  
       case TOK_LET:  
         instrument_let_definition(node->pn_left->pn_left, f, 0);  
         break;  
       case TOK_NAME:  
         instrument_expression(node->pn_left->pn_left, f);  
         break;  
       default:  
         /* this is undocumented: for (x.value in y) */  
         instrument_expression(node->pn_left->pn_left, f);  
         break;  
 /*  
       default:  
         fprintf(stderr, "unexpected node type: %d\n", node->pn_left->pn_left->pn_type);  
         abort();  
         break;  
 */  
       }  
       Stream_write_string(f, " in ");  
       instrument_expression(node->pn_left->pn_right, f);  
1007        break;        break;
1008      case TOK_RESERVED:      case TOK_RESERVED:
1009        /* for (;;) */        /* for (;;) */
1010        assert(node->pn_left->pn_arity == PN_TERNARY);        assert(node->pn_left->pn_arity == PN_TERNARY);
1011          Stream_write_string(f, "for (");
1012        if (node->pn_left->pn_kid1) {        if (node->pn_left->pn_kid1) {
1013          switch (node->pn_left->pn_kid1->pn_type) {          instrument_expression(node->pn_left->pn_kid1, f);
         case TOK_VAR:  
           instrument_var_statement(node->pn_left->pn_kid1, f, 0);  
           break;  
         case TOK_LET:  
           instrument_let_definition(node->pn_left->pn_kid1, f, 0);  
           break;  
         default:  
           instrument_expression(node->pn_left->pn_kid1, f);  
           break;  
         }  
1014        }        }
1015        Stream_write_string(f, ";");        Stream_write_string(f, ";");
1016        if (node->pn_left->pn_kid2) {        if (node->pn_left->pn_kid2) {
# Line 865  Line 1022 
1022          Stream_write_char(f, ' ');          Stream_write_char(f, ' ');
1023          instrument_expression(node->pn_left->pn_kid3, f);          instrument_expression(node->pn_left->pn_kid3, f);
1024        }        }
1025          Stream_write_char(f, ')');
1026        break;        break;
1027      default:      default:
1028        abort();        abort();
1029        break;        break;
1030      }      }
1031      Stream_write_string(f, ") {\n");      Stream_write_string(f, " {\n");
1032      instrument_statement(node->pn_right, f, indent + 2, false);      instrument_statement(node->pn_right, f, indent + 2, false);
1033      Stream_write_string(f, "}\n");      Stream_write_string(f, "}\n");
1034      break;      break;
# Line 945  Line 1103 
1103      Stream_write_string(f, "}\n");      Stream_write_string(f, "}\n");
1104      break;      break;
1105    case TOK_VAR:    case TOK_VAR:
1106      instrument_var_statement(node, f, indent);      Stream_printf(f, "%*s", indent, "");
1107        instrument_expression(node, f);
1108      Stream_write_string(f, ";\n");      Stream_write_string(f, ";\n");
1109      break;      break;
1110    case TOK_RETURN:    case TOK_RETURN:
# Line 967  Line 1126 
1126      Stream_write_string(f, ";\n");      Stream_write_string(f, ";\n");
1127      break;      break;
1128    case TOK_COLON:    case TOK_COLON:
1129      {
1130      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 ...  
     */  
1131      Stream_printf(f, "%*s", indent < 2? 0: indent - 2, "");      Stream_printf(f, "%*s", indent < 2? 0: indent - 2, "");
1132      print_string_atom(node->pn_atom, f);      print_string_atom(node->pn_atom, f);
1133      Stream_write_string(f, ":\n");      Stream_write_string(f, ":\n");
1134      /*      JSParseNode * labelled = node->pn_expr;
1135      ... use output_statement instead of instrument_statement.      if (labelled->pn_type == TOK_LEXICALSCOPE) {
1136      */        labelled = labelled->pn_expr;
1137      output_statement(node->pn_expr, f, indent, false);      }
1138        if (labelled->pn_type == TOK_LC) {
1139          /* labelled block */
1140          Stream_printf(f, "%*s", indent, "");
1141          Stream_write_string(f, "{\n");
1142          instrument_statement(labelled, f, indent + 2, false);
1143          Stream_printf(f, "%*s", indent, "");
1144          Stream_write_string(f, "}\n");
1145        }
1146        else {
1147          /*
1148          This one is tricky: can't output instrumentation between the label and the
1149          statement it's supposed to label, so use output_statement instead of
1150          instrument_statement.
1151          */
1152          output_statement(labelled, f, indent, false);
1153        }
1154      break;      break;
1155      }
1156    case TOK_LEXICALSCOPE:    case TOK_LEXICALSCOPE:
1157      /* let statement */      /* let statement */
1158      assert(node->pn_arity == PN_NAME);      assert(node->pn_arity == PN_NAME);
# Line 1021  Line 1194 
1194        break;        break;
1195      case PN_LIST:      case PN_LIST:
1196        /* let definition */        /* let definition */
1197        instrument_let_definition(node, f, indent);        Stream_printf(f, "%*s", indent, "");
1198          instrument_expression(node, f);
1199        Stream_write_string(f, ";\n");        Stream_write_string(f, ";\n");
1200        break;        break;
1201      default:      default:
# Line 1029  Line 1203 
1203        break;        break;
1204      }      }
1205      break;      break;
1206      case TOK_DEBUGGER:
1207        Stream_printf(f, "%*s", indent, "");
1208        Stream_write_string(f, "debugger;\n");
1209        break;
1210    default:    default:
1211      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);
1212    }    }
1213  }  }
1214    
# Line 1043  Line 1221 
1221    if (node->pn_type != TOK_LC && node->pn_type != TOK_LEXICALSCOPE) {    if (node->pn_type != TOK_LC && node->pn_type != TOK_LEXICALSCOPE) {
1222      uint16_t line = node->pn_pos.begin.lineno;      uint16_t line = node->pn_pos.begin.lineno;
1223      if (line > num_lines) {      if (line > num_lines) {
1224        fatal("%s: script contains more than 65,535 lines", file_id);        fatal("file %s contains more than 65,535 lines", file_id);
1225      }      }
1226    
1227      /* the root node has line number 0 */      /* the root node has line number 0 */
# Line 1091  Line 1269 
1269  }  }
1270    
1271  static void error_reporter(JSContext * context, const char * message, JSErrorReport * report) {  static void error_reporter(JSContext * context, const char * message, JSErrorReport * report) {
1272    fprintf(stderr, "jscoverage: parse error: line %u: %s\n", report->lineno, message);    warn_source(file_id, report->lineno, "%s", message);
1273  }  }
1274    
1275  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 1100  Line 1278 
1278    /* parse the javascript */    /* parse the javascript */
1279    JSParseContext parse_context;    JSParseContext parse_context;
1280    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)) {
1281      fatal("cannot create token stream from file: %s", file_id);      fatal("cannot create token stream from file %s", file_id);
1282    }    }
1283    JSErrorReporter old_error_reporter = JS_SetErrorReporter(context, error_reporter);    JSErrorReporter old_error_reporter = JS_SetErrorReporter(context, error_reporter);
1284    JSParseNode * node = js_ParseScript(context, global, &parse_context);    JSParseNode * node = js_ParseScript(context, global, &parse_context);
1285    if (node == NULL) {    if (node == NULL) {
1286      js_ReportUncaughtException(context);      js_ReportUncaughtException(context);
1287      fatal("parse error in file: %s", file_id);      fatal("parse error in file %s", file_id);
1288    }    }
1289    JS_SetErrorReporter(context, old_error_reporter);    JS_SetErrorReporter(context, old_error_reporter);
1290    num_lines = node->pn_pos.end.lineno;    num_lines = node->pn_pos.end.lineno;
# Line 1127  Line 1305 
1305    size_t i = 0;    size_t i = 0;
1306    while (i < num_characters) {    while (i < num_characters) {
1307      if (line_number == UINT16_MAX) {      if (line_number == UINT16_MAX) {
1308        fatal("%s: script has more than 65,535 lines", file_id);        fatal("file %s contains more than 65,535 lines", file_id);
1309      }      }
1310      line_number++;      line_number++;
1311      size_t line_start = i;      size_t line_start = i;
# Line 1194  Line 1372 
1372    
1373    /* write line number info to the output */    /* write line number info to the output */
1374    Stream_write_string(output, "/* automatically generated by JSCoverage - do not edit */\n");    Stream_write_string(output, "/* automatically generated by JSCoverage - do not edit */\n");
1375    Stream_write_string(output, "if (! top._$jscoverage) {\n  top._$jscoverage = {};\n}\n");    if (jscoverage_mozilla) {
1376    Stream_write_string(output, "var _$jscoverage = top._$jscoverage;\n");      Stream_write_string(output, "try {\n");
1377        Stream_write_string(output, "  Components.utils.import('resource://gre/modules/jscoverage.jsm');\n");
1378        Stream_printf(output, "  dump('%s: successfully imported jscoverage module\\n');\n", id);
1379        Stream_write_string(output, "}\n");
1380        Stream_write_string(output, "catch (e) {\n");
1381        Stream_write_string(output, "  _$jscoverage = {};\n");
1382        Stream_printf(output, "  dump('%s: failed to import jscoverage module - coverage not available for this file\\n');\n", id);
1383        Stream_write_string(output, "}\n");
1384      }
1385      else {
1386        Stream_write_string(output, "if (! top._$jscoverage) {\n  top._$jscoverage = {};\n}\n");
1387        Stream_write_string(output, "var _$jscoverage = top._$jscoverage;\n");
1388      }
1389    Stream_printf(output, "if (! _$jscoverage['%s']) {\n", file_id);    Stream_printf(output, "if (! _$jscoverage['%s']) {\n", file_id);
1390    Stream_printf(output, "  _$jscoverage['%s'] = [];\n", file_id);    Stream_printf(output, "  _$jscoverage['%s'] = [];\n", file_id);
1391    for (int i = 0; i < num_lines; i++) {    for (int i = 0; i < num_lines; i++) {

Legend:
Removed from v.341  
changed lines
  Added in v.376

  ViewVC Help
Powered by ViewVC 1.1.24