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

Diff of /trunk/instrument-js.cpp

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

trunk/instrument-js.c revision 374 by siliconforks, Mon Oct 27 21:42:58 2008 UTC trunk/instrument-js.cpp revision 401 by siliconforks, Tue Dec 9 09:47:21 2008 UTC
# Line 1  Line 1 
1  /*  /*
2      instrument-js.c - JavaScript instrumentation routines      instrument-js.cpp - JavaScript instrumentation routines
3      Copyright (C) 2007, 2008 siliconforks.com      Copyright (C) 2007, 2008 siliconforks.com
4    
5      This program is free software; you can redistribute it and/or modify      This program is free software; you can redistribute it and/or modify
# Line 22  Line 22 
22  #include "instrument-js.h"  #include "instrument-js.h"
23    
24  #include <assert.h>  #include <assert.h>
25    #include <math.h>
26  #include <stdlib.h>  #include <stdlib.h>
27  #include <string.h>  #include <string.h>
28    
# Line 267  Line 268 
268    }    }
269  }  }
270    
271  static void instrument_expression(JSParseNode * node, Stream * f);  static void output_expression(JSParseNode * node, Stream * f, bool parenthesize_object_literals);
272  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);
273  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);
274    
# Line 284  Line 285 
285      Stream_write_string(f, "each ");      Stream_write_string(f, "each ");
286    }    }
287    Stream_write_char(f, '(');    Stream_write_char(f, '(');
288    instrument_expression(node->pn_left, f);    output_expression(node->pn_left, f, false);
289    Stream_write_char(f, ')');    Stream_write_char(f, ')');
290  }  }
291    
# Line 311  Line 312 
312      p = p->pn_kid;      p = p->pn_kid;
313    }    }
314    
315    instrument_expression(p, f);    output_expression(p, f, false);
316    p = for_node;    p = for_node;
317    while (p->pn_type == TOK_FOR) {    while (p->pn_type == TOK_FOR) {
318      Stream_write_char(f, ' ');      Stream_write_char(f, ' ');
# Line 320  Line 321 
321    }    }
322    if (if_node) {    if (if_node) {
323      Stream_write_string(f, " if (");      Stream_write_string(f, " if (");
324      instrument_expression(if_node->pn_kid1, f);      output_expression(if_node->pn_kid1, f, false);
325      Stream_write_char(f, ')');      Stream_write_char(f, ')');
326    }    }
327  }  }
# Line 366  Line 367 
367      if (param == NULL) {      if (param == NULL) {
368        destructuring = true;        destructuring = true;
369        JSParseNode * expression = NULL;        JSParseNode * expression = NULL;
370        assert(node->pn_body->pn_type == TOK_LC || node->pn_body->pn_type == TOK_BODY);        assert(node->pn_body->pn_type == TOK_LC || node->pn_body->pn_type == TOK_SEQ);
371        JSParseNode * semi = node->pn_body->pn_head;        JSParseNode * semi = node->pn_body->pn_head;
372        assert(semi->pn_type == TOK_SEMI);        assert(semi->pn_type == TOK_SEMI);
373        JSParseNode * comma = semi->pn_kid;        JSParseNode * comma = semi->pn_kid;
# Line 381  Line 382 
382          }          }
383        }        }
384        assert(expression != NULL);        assert(expression != NULL);
385        instrument_expression(expression, f);        output_expression(expression, f, false);
386      }      }
387      else {      else {
388        print_string_atom(param, f);        print_string_atom(param, f);
# Line 393  Line 394 
394    /* function body */    /* function body */
395    if (function->flags & JSFUN_EXPR_CLOSURE) {    if (function->flags & JSFUN_EXPR_CLOSURE) {
396      /* expression closure - use output_statement instead of instrument_statement */      /* expression closure - use output_statement instead of instrument_statement */
397      if (node->pn_body->pn_type == TOK_BODY) {      if (node->pn_body->pn_type == TOK_SEQ) {
398        assert(node->pn_body->pn_arity == PN_LIST);        assert(node->pn_body->pn_arity == PN_LIST);
399        assert(node->pn_body->pn_count == 2);        assert(node->pn_body->pn_count == 2);
400        output_statement(node->pn_body->pn_head->pn_next, f, indent + 2, false);        output_statement(node->pn_body->pn_head->pn_next, f, indent + 2, false);
# Line 414  Line 415 
415      }      }
416    }    }
417    
418    Stream_write_string(f, "}\n");    Stream_write_char(f, '}');
419  }  }
420    
421  static void instrument_function_call(JSParseNode * node, Stream * f) {  static void instrument_function_call(JSParseNode * node, Stream * f) {
# Line 433  Line 434 
434        Stream_write_char(f, ')');        Stream_write_char(f, ')');
435        return;        return;
436      }      }
     else {  
       Stream_write_char(f, '(');  
       instrument_expression(function_node, f);  
       Stream_write_char(f, ')');  
     }  
   }  
   else {  
     instrument_expression(function_node, f);  
437    }    }
438      output_expression(function_node, f, false);
439    Stream_write_char(f, '(');    Stream_write_char(f, '(');
440    for (struct JSParseNode * p = function_node->pn_next; p != NULL; p = p->pn_next) {    for (struct JSParseNode * p = function_node->pn_next; p != NULL; p = p->pn_next) {
441      if (p != node->pn_head->pn_next) {      if (p != node->pn_head->pn_next) {
442        Stream_write_string(f, ", ");        Stream_write_string(f, ", ");
443      }      }
444      instrument_expression(p, f);      output_expression(p, f, false);
445    }    }
446    Stream_write_char(f, ')');    Stream_write_char(f, ')');
447  }  }
# Line 455  Line 449 
449  static void instrument_declarations(JSParseNode * list, Stream * f) {  static void instrument_declarations(JSParseNode * list, Stream * f) {
450    assert(list->pn_arity == PN_LIST);    assert(list->pn_arity == PN_LIST);
451    for (JSParseNode * p = list->pn_head; p != NULL; p = p->pn_next) {    for (JSParseNode * p = list->pn_head; p != NULL; p = p->pn_next) {
452      switch (p->pn_type) {      if (p != list->pn_head) {
453      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:  
       /* destructuring */  
       instrument_expression(p->pn_left, f);  
       Stream_write_string(f, " = ");  
       instrument_expression(p->pn_right, f);  
       break;  
     case TOK_RB:  
     case TOK_RC:  
       /* destructuring */  
       instrument_expression(p, f);  
       break;  
     default:  
       abort();  
       break;  
454      }      }
455        output_expression(p, f, false);
456    }    }
457  }  }
458    
# Line 498  Line 469 
469  TOK_INSTANCEOF  binary  TOK_INSTANCEOF  binary
470  TOK_IN          binary  TOK_IN          binary
471  */  */
472  static void instrument_expression(JSParseNode * node, Stream * f) {  static void output_expression(JSParseNode * node, Stream * f, bool parenthesize_object_literals) {
473    switch (node->pn_type) {    switch (node->pn_type) {
474    case TOK_FUNCTION:    case TOK_FUNCTION:
475        Stream_write_char(f, '(');
476      instrument_function(node, f, 0, FUNCTION_NORMAL);      instrument_function(node, f, 0, FUNCTION_NORMAL);
477        Stream_write_char(f, ')');
478      break;      break;
479    case TOK_COMMA:    case TOK_COMMA:
480      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) {
481        if (p != node->pn_head) {        if (p != node->pn_head) {
482          Stream_write_string(f, ", ");          Stream_write_string(f, ", ");
483        }        }
484        instrument_expression(p, f);        output_expression(p, f, parenthesize_object_literals);
485      }      }
486      break;      break;
487    case TOK_ASSIGN:    case TOK_ASSIGN:
488      if (node->pn_left->pn_type == TOK_RC) {      output_expression(node->pn_left, f, parenthesize_object_literals);
       /* destructuring assignment with object literal must be in parentheses */  
       Stream_write_char(f, '(');  
       instrument_expression(node->pn_left, f);  
       Stream_write_char(f, ')');  
     }  
     else {  
       instrument_expression(node->pn_left, f);  
     }  
489      Stream_write_char(f, ' ');      Stream_write_char(f, ' ');
490      switch (node->pn_op) {      switch (node->pn_op) {
491      case JSOP_ADD:      case JSOP_ADD:
# Line 541  Line 506 
506        break;        break;
507      }      }
508      Stream_write_string(f, "= ");      Stream_write_string(f, "= ");
509      instrument_expression(node->pn_right, f);      output_expression(node->pn_right, f, false);
510      break;      break;
511    case TOK_HOOK:    case TOK_HOOK:
512      instrument_expression(node->pn_kid1, f);      output_expression(node->pn_kid1, f, parenthesize_object_literals);
513      Stream_write_string(f, "? ");      Stream_write_string(f, "? ");
514      instrument_expression(node->pn_kid2, f);      output_expression(node->pn_kid2, f, false);
515      Stream_write_string(f, ": ");      Stream_write_string(f, ": ");
516      instrument_expression(node->pn_kid3, f);      output_expression(node->pn_kid3, f, false);
517      break;      break;
518    case TOK_OR:    case TOK_OR:
519    case TOK_AND:    case TOK_AND:
# Line 564  Line 529 
529    case TOK_DIVOP:    case TOK_DIVOP:
530      switch (node->pn_arity) {      switch (node->pn_arity) {
531      case PN_BINARY:      case PN_BINARY:
532        instrument_expression(node->pn_left, f);        output_expression(node->pn_left, f, parenthesize_object_literals);
533        Stream_printf(f, " %s ", get_op(node->pn_op));        Stream_printf(f, " %s ", get_op(node->pn_op));
534        instrument_expression(node->pn_right, f);        output_expression(node->pn_right, f, false);
535        break;        break;
536      case PN_LIST:      case PN_LIST:
537        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) {
538          if (p != node->pn_head) {          if (p == node->pn_head) {
539              output_expression(p, f, parenthesize_object_literals);
540            }
541            else {
542            Stream_printf(f, " %s ", get_op(node->pn_op));            Stream_printf(f, " %s ", get_op(node->pn_op));
543              output_expression(p, f, false);
544          }          }
         instrument_expression(p, f);  
545        }        }
546        break;        break;
547      default:      default:
# Line 583  Line 551 
551    case TOK_UNARYOP:    case TOK_UNARYOP:
552      switch (node->pn_op) {      switch (node->pn_op) {
553      case JSOP_NEG:      case JSOP_NEG:
554        Stream_write_char(f, '-');        Stream_write_string(f, "- ");
555        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, false);
556        break;        break;
557      case JSOP_POS:      case JSOP_POS:
558        Stream_write_char(f, '+');        Stream_write_string(f, "+ ");
559        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, false);
560        break;        break;
561      case JSOP_NOT:      case JSOP_NOT:
562        Stream_write_char(f, '!');        Stream_write_string(f, "! ");
563        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, false);
564        break;        break;
565      case JSOP_BITNOT:      case JSOP_BITNOT:
566        Stream_write_char(f, '~');        Stream_write_string(f, "~ ");
567        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, false);
568        break;        break;
569      case JSOP_TYPEOF:      case JSOP_TYPEOF:
570        Stream_write_string(f, "typeof ");        Stream_write_string(f, "typeof ");
571        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, false);
572        break;        break;
573      case JSOP_VOID:      case JSOP_VOID:
574        Stream_write_string(f, "void ");        Stream_write_string(f, "void ");
575        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, false);
576        break;        break;
577      default:      default:
578        fatal_source(file_id, node->pn_pos.begin.lineno, "unknown operator (%d)", node->pn_op);        fatal_source(file_id, node->pn_pos.begin.lineno, "unknown operator (%d)", node->pn_op);
# Line 621  Line 589 
589      case JSOP_INCPROP:      case JSOP_INCPROP:
590      case JSOP_INCELEM:      case JSOP_INCELEM:
591        Stream_write_string(f, "++");        Stream_write_string(f, "++");
592        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, false);
593        break;        break;
594      case JSOP_DECNAME:      case JSOP_DECNAME:
595      case JSOP_DECPROP:      case JSOP_DECPROP:
596      case JSOP_DECELEM:      case JSOP_DECELEM:
597        Stream_write_string(f, "--");        Stream_write_string(f, "--");
598        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, false);
599        break;        break;
600      case JSOP_NAMEINC:      case JSOP_NAMEINC:
601      case JSOP_PROPINC:      case JSOP_PROPINC:
602      case JSOP_ELEMINC:      case JSOP_ELEMINC:
603        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, parenthesize_object_literals);
604        Stream_write_string(f, "++");        Stream_write_string(f, "++");
605        break;        break;
606      case JSOP_NAMEDEC:      case JSOP_NAMEDEC:
607      case JSOP_PROPDEC:      case JSOP_PROPDEC:
608      case JSOP_ELEMDEC:      case JSOP_ELEMDEC:
609        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, parenthesize_object_literals);
610        Stream_write_string(f, "--");        Stream_write_string(f, "--");
611        break;        break;
612      default:      default:
# Line 652  Line 620 
620      break;      break;
621    case TOK_DELETE:    case TOK_DELETE:
622      Stream_write_string(f, "delete ");      Stream_write_string(f, "delete ");
623      instrument_expression(node->pn_kid, f);      output_expression(node->pn_kid, f, false);
624      break;      break;
625    case TOK_DOT:    case TOK_DOT:
626        /* numeric literals must be parenthesized */
627        switch (node->pn_expr->pn_type) {
628        case TOK_NUMBER:
629          Stream_write_char(f, '(');
630          output_expression(node->pn_expr, f, false);
631          Stream_write_char(f, ')');
632          break;
633        default:
634          output_expression(node->pn_expr, f, true);
635          break;
636        }
637      /*      /*
638      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'
639      contains illegal characters, we have to use the subscript syntax instead of      contains illegal characters, we have to use the subscript syntax instead of
640      the dot syntax.      the dot syntax.
641      */      */
     instrument_expression(node->pn_expr, f);  
642      assert(ATOM_IS_STRING(node->pn_atom));      assert(ATOM_IS_STRING(node->pn_atom));
643      {      {
644        JSString * s = ATOM_TO_STRING(node->pn_atom);        JSString * s = ATOM_TO_STRING(node->pn_atom);
# Line 689  Line 667 
667      }      }
668      break;      break;
669    case TOK_LB:    case TOK_LB:
670      instrument_expression(node->pn_left, f);      output_expression(node->pn_left, f, false);
671      Stream_write_char(f, '[');      Stream_write_char(f, '[');
672      instrument_expression(node->pn_right, f);      output_expression(node->pn_right, f, false);
673      Stream_write_char(f, ']');      Stream_write_char(f, ']');
674      break;      break;
675    case TOK_LP:    case TOK_LP:
# Line 705  Line 683 
683        }        }
684        /* TOK_COMMA is a special case: a hole in the array */        /* TOK_COMMA is a special case: a hole in the array */
685        if (p->pn_type != TOK_COMMA) {        if (p->pn_type != TOK_COMMA) {
686          instrument_expression(p, f);          output_expression(p, f, false);
687        }        }
688      }      }
689      if (node->pn_extra == PNX_ENDCOMMA) {      if (node->pn_extra == PNX_ENDCOMMA) {
# Line 714  Line 692 
692      Stream_write_char(f, ']');      Stream_write_char(f, ']');
693      break;      break;
694    case TOK_RC:    case TOK_RC:
695        if (parenthesize_object_literals) {
696          Stream_write_char(f, '(');
697        }
698      Stream_write_char(f, '{');      Stream_write_char(f, '{');
699      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) {
700        if (p->pn_type != TOK_COLON) {        if (p->pn_type != TOK_COLON) {
# Line 733  Line 714 
714          else {          else {
715            Stream_write_string(f, "set ");            Stream_write_string(f, "set ");
716          }          }
717          instrument_expression(p->pn_left, f);          output_expression(p->pn_left, f, false);
718            Stream_write_char(f, ' ');
719          if (p->pn_right->pn_type != TOK_FUNCTION) {          if (p->pn_right->pn_type != TOK_FUNCTION) {
720            fatal_source(file_id, p->pn_pos.begin.lineno, "expected function");            fatal_source(file_id, p->pn_pos.begin.lineno, "expected function");
721          }          }
722          instrument_function(p->pn_right, f, 0, FUNCTION_GETTER_OR_SETTER);          instrument_function(p->pn_right, f, 0, FUNCTION_GETTER_OR_SETTER);
723          break;          break;
724        default:        default:
725          instrument_expression(p->pn_left, f);          output_expression(p->pn_left, f, false);
726          Stream_write_string(f, ": ");          Stream_write_string(f, ": ");
727          instrument_expression(p->pn_right, f);          output_expression(p->pn_right, f, false);
728          break;          break;
729        }        }
730      }      }
731      Stream_write_char(f, '}');      Stream_write_char(f, '}');
732        if (parenthesize_object_literals) {
733          Stream_write_char(f, ')');
734        }
735      break;      break;
736    case TOK_RP:    case TOK_RP:
737      Stream_write_char(f, '(');      Stream_write_char(f, '(');
738      instrument_expression(node->pn_kid, f);      output_expression(node->pn_kid, f, false);
739      Stream_write_char(f, ')');      Stream_write_char(f, ')');
740      break;      break;
741    case TOK_NAME:    case TOK_NAME:
742      print_string_atom(node->pn_atom, f);      print_string_atom(node->pn_atom, f);
743        if (node->pn_expr != NULL) {
744          Stream_write_string(f, " = ");
745          output_expression(node->pn_expr, f, false);
746        }
747      break;      break;
748    case TOK_STRING:    case TOK_STRING:
749      print_quoted_string_atom(node->pn_atom, f);      print_quoted_string_atom(node->pn_atom, f);
# Line 776  Line 765 
765      To keep the output simple, special-case zero.      To keep the output simple, special-case zero.
766      */      */
767      if (node->pn_dval == 0.0) {      if (node->pn_dval == 0.0) {
768        Stream_write_string(f, "0");        if (signbit(node->pn_dval)) {
769            Stream_write_string(f, "-0");
770          }
771          else {
772            Stream_write_string(f, "0");
773          }
774        }
775        else if (node->pn_dval == INFINITY) {
776          Stream_write_string(f, "Number.POSITIVE_INFINITY");
777        }
778        else if (node->pn_dval == -INFINITY) {
779          Stream_write_string(f, "Number.NEGATIVE_INFINITY");
780        }
781        else if (isnan(node->pn_dval)) {
782          Stream_write_string(f, "Number.NaN");
783      }      }
784      else {      else {
785        Stream_printf(f, "%.15g", node->pn_dval);        Stream_printf(f, "%.15g", node->pn_dval);
# Line 802  Line 805 
805      }      }
806      break;      break;
807    case TOK_INSTANCEOF:    case TOK_INSTANCEOF:
808      instrument_expression(node->pn_left, f);      output_expression(node->pn_left, f, parenthesize_object_literals);
809      Stream_write_string(f, " instanceof ");      Stream_write_string(f, " instanceof ");
810      instrument_expression(node->pn_right, f);      output_expression(node->pn_right, f, false);
811      break;      break;
812    case TOK_IN:    case TOK_IN:
813      instrument_expression(node->pn_left, f);      output_expression(node->pn_left, f, false);
814      Stream_write_string(f, " in ");      Stream_write_string(f, " in ");
815      instrument_expression(node->pn_right, f);      output_expression(node->pn_right, f, false);
816      break;      break;
817    case TOK_LEXICALSCOPE:    case TOK_LEXICALSCOPE:
818      assert(node->pn_arity == PN_NAME);      assert(node->pn_arity == PN_NAME);
# Line 820  Line 823 
823      assert(node->pn_expr->pn_left->pn_arity == PN_LIST);      assert(node->pn_expr->pn_left->pn_arity == PN_LIST);
824      instrument_declarations(node->pn_expr->pn_left, f);      instrument_declarations(node->pn_expr->pn_left, f);
825      Stream_write_string(f, ") ");      Stream_write_string(f, ") ");
826      instrument_expression(node->pn_expr->pn_right, f);      output_expression(node->pn_expr->pn_right, f, true);
827      break;      break;
828    case TOK_YIELD:    case TOK_YIELD:
829      assert(node->pn_arity == PN_UNARY);      assert(node->pn_arity == PN_UNARY);
830      Stream_write_string(f, "yield");      Stream_write_string(f, "yield");
831      if (node->pn_kid != NULL) {      if (node->pn_kid != NULL) {
832        Stream_write_char(f, ' ');        Stream_write_char(f, ' ');
833        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, true);
834      }      }
835      break;      break;
836    case TOK_ARRAYCOMP:    case TOK_ARRAYCOMP:
# Line 869  Line 872 
872    switch (node->pn_type) {    switch (node->pn_type) {
873    case TOK_FUNCTION:    case TOK_FUNCTION:
874      instrument_function(node, f, indent, FUNCTION_NORMAL);      instrument_function(node, f, indent, FUNCTION_NORMAL);
875        Stream_write_char(f, '\n');
876      break;      break;
877    case TOK_LC:    case TOK_LC:
878      assert(node->pn_arity == PN_LIST);      assert(node->pn_arity == PN_LIST);
# Line 899  Line 903 
903    
904      Stream_printf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
905      Stream_write_string(f, "if (");      Stream_write_string(f, "if (");
906      instrument_expression(node->pn_kid1, f);      output_expression(node->pn_kid1, f, false);
907      Stream_write_string(f, ") {\n");      Stream_write_string(f, ") {\n");
908      if (is_jscoverage_if && node->pn_kid3) {      if (is_jscoverage_if && node->pn_kid3) {
909        uint16_t else_start = node->pn_kid3->pn_pos.begin.lineno;        uint16_t else_start = node->pn_kid3->pn_pos.begin.lineno;
# Line 936  Line 940 
940      assert(node->pn_arity == PN_BINARY);      assert(node->pn_arity == PN_BINARY);
941      Stream_printf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
942      Stream_write_string(f, "switch (");      Stream_write_string(f, "switch (");
943      instrument_expression(node->pn_left, f);      output_expression(node->pn_left, f, false);
944      Stream_write_string(f, ") {\n");      Stream_write_string(f, ") {\n");
945      {      {
946        JSParseNode * list = node->pn_right;        JSParseNode * list = node->pn_right;
# Line 948  Line 952 
952          switch (p->pn_type) {          switch (p->pn_type) {
953          case TOK_CASE:          case TOK_CASE:
954            Stream_write_string(f, "case ");            Stream_write_string(f, "case ");
955            instrument_expression(p->pn_left, f);            output_expression(p->pn_left, f, false);
956            Stream_write_string(f, ":\n");            Stream_write_string(f, ":\n");
957            break;            break;
958          case TOK_DEFAULT:          case TOK_DEFAULT:
# Line 972  Line 976 
976      assert(node->pn_arity == PN_BINARY);      assert(node->pn_arity == PN_BINARY);
977      Stream_printf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
978      Stream_write_string(f, "while (");      Stream_write_string(f, "while (");
979      instrument_expression(node->pn_left, f);      output_expression(node->pn_left, f, false);
980      Stream_write_string(f, ") {\n");      Stream_write_string(f, ") {\n");
981      instrument_statement(node->pn_right, f, indent + 2, false);      instrument_statement(node->pn_right, f, indent + 2, false);
982      Stream_write_string(f, "}\n");      Stream_write_string(f, "}\n");
# Line 985  Line 989 
989      Stream_write_string(f, "}\n");      Stream_write_string(f, "}\n");
990      Stream_printf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
991      Stream_write_string(f, "while (");      Stream_write_string(f, "while (");
992      instrument_expression(node->pn_right, f);      output_expression(node->pn_right, f, false);
993      Stream_write_string(f, ");\n");      Stream_write_string(f, ");\n");
994      break;      break;
995    case TOK_FOR:    case TOK_FOR:
# Line 997  Line 1001 
1001        assert(node->pn_left->pn_arity == PN_BINARY);        assert(node->pn_left->pn_arity == PN_BINARY);
1002        output_for_in(node, f);        output_for_in(node, f);
1003        break;        break;
1004      case TOK_RESERVED:      case TOK_FORHEAD:
1005        /* for (;;) */        /* for (;;) */
1006        assert(node->pn_left->pn_arity == PN_TERNARY);        assert(node->pn_left->pn_arity == PN_TERNARY);
1007        Stream_write_string(f, "for (");        Stream_write_string(f, "for (");
1008        if (node->pn_left->pn_kid1) {        if (node->pn_left->pn_kid1) {
1009          instrument_expression(node->pn_left->pn_kid1, f);          output_expression(node->pn_left->pn_kid1, f, false);
1010        }        }
1011        Stream_write_string(f, ";");        Stream_write_string(f, ";");
1012        if (node->pn_left->pn_kid2) {        if (node->pn_left->pn_kid2) {
1013          Stream_write_char(f, ' ');          Stream_write_char(f, ' ');
1014          instrument_expression(node->pn_left->pn_kid2, f);          output_expression(node->pn_left->pn_kid2, f, false);
1015        }        }
1016        Stream_write_string(f, ";");        Stream_write_string(f, ";");
1017        if (node->pn_left->pn_kid3) {        if (node->pn_left->pn_kid3) {
1018          Stream_write_char(f, ' ');          Stream_write_char(f, ' ');
1019          instrument_expression(node->pn_left->pn_kid3, f);          output_expression(node->pn_left->pn_kid3, f, false);
1020        }        }
1021        Stream_write_char(f, ')');        Stream_write_char(f, ')');
1022        break;        break;
# Line 1028  Line 1032 
1032      assert(node->pn_arity == PN_UNARY);      assert(node->pn_arity == PN_UNARY);
1033      Stream_printf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
1034      Stream_write_string(f, "throw ");      Stream_write_string(f, "throw ");
1035      instrument_expression(node->pn_u.unary.kid, f);      output_expression(node->pn_u.unary.kid, f, false);
1036      Stream_write_string(f, ";\n");      Stream_write_string(f, ";\n");
1037      break;      break;
1038    case TOK_TRY:    case TOK_TRY:
# Line 1041  Line 1045 
1045        assert(node->pn_kid2->pn_type == TOK_RESERVED);        assert(node->pn_kid2->pn_type == TOK_RESERVED);
1046        for (JSParseNode * scope = node->pn_kid2->pn_head; scope != NULL; scope = scope->pn_next) {        for (JSParseNode * scope = node->pn_kid2->pn_head; scope != NULL; scope = scope->pn_next) {
1047          assert(scope->pn_type == TOK_LEXICALSCOPE);          assert(scope->pn_type == TOK_LEXICALSCOPE);
1048          JSParseNode * catch = scope->pn_expr;          JSParseNode * catch_node = scope->pn_expr;
1049          assert(catch->pn_type == TOK_CATCH);          assert(catch_node->pn_type == TOK_CATCH);
1050          Stream_printf(f, "%*s", indent, "");          Stream_printf(f, "%*s", indent, "");
1051          Stream_write_string(f, "catch (");          Stream_write_string(f, "catch (");
1052          /* this may not be a name - destructuring assignment */          output_expression(catch_node->pn_kid1, f, false);
1053          /*          if (catch_node->pn_kid2) {
         assert(catch->pn_kid1->pn_arity == PN_NAME);  
         print_string_atom(catch->pn_kid1->pn_atom, f);  
         */  
         instrument_expression(catch->pn_kid1, f);  
         if (catch->pn_kid2) {  
1054            Stream_write_string(f, " if ");            Stream_write_string(f, " if ");
1055            instrument_expression(catch->pn_kid2, f);            output_expression(catch_node->pn_kid2, f, false);
1056          }          }
1057          Stream_write_string(f, ") {\n");          Stream_write_string(f, ") {\n");
1058          instrument_statement(catch->pn_kid3, f, indent + 2, false);          instrument_statement(catch_node->pn_kid3, f, indent + 2, false);
1059          Stream_printf(f, "%*s", indent, "");          Stream_printf(f, "%*s", indent, "");
1060          Stream_write_string(f, "}\n");          Stream_write_string(f, "}\n");
1061        }        }
# Line 1077  Line 1076 
1076      assert(node->pn_arity == PN_NAME || node->pn_arity == PN_NULLARY);      assert(node->pn_arity == PN_NAME || node->pn_arity == PN_NULLARY);
1077      Stream_printf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
1078      Stream_write_string(f, node->pn_type == TOK_BREAK? "break": "continue");      Stream_write_string(f, node->pn_type == TOK_BREAK? "break": "continue");
1079      JSAtom * atom = node->pn_u.name.atom;      if (node->pn_atom != NULL) {
     if (atom != NULL) {  
1080        Stream_write_char(f, ' ');        Stream_write_char(f, ' ');
1081        print_string_atom(node->pn_atom, f);        print_string_atom(node->pn_atom, f);
1082      }      }
# Line 1088  Line 1086 
1086      assert(node->pn_arity == PN_BINARY);      assert(node->pn_arity == PN_BINARY);
1087      Stream_printf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
1088      Stream_write_string(f, "with (");      Stream_write_string(f, "with (");
1089      instrument_expression(node->pn_left, f);      output_expression(node->pn_left, f, false);
1090      Stream_write_string(f, ") {\n");      Stream_write_string(f, ") {\n");
1091      instrument_statement(node->pn_right, f, indent + 2, false);      instrument_statement(node->pn_right, f, indent + 2, false);
1092      Stream_printf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
# Line 1096  Line 1094 
1094      break;      break;
1095    case TOK_VAR:    case TOK_VAR:
1096      Stream_printf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
1097      instrument_expression(node, f);      output_expression(node, f, false);
1098      Stream_write_string(f, ";\n");      Stream_write_string(f, ";\n");
1099      break;      break;
1100    case TOK_RETURN:    case TOK_RETURN:
# Line 1105  Line 1103 
1103      Stream_write_string(f, "return");      Stream_write_string(f, "return");
1104      if (node->pn_kid != NULL) {      if (node->pn_kid != NULL) {
1105        Stream_write_char(f, ' ');        Stream_write_char(f, ' ');
1106        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, true);
1107      }      }
1108      Stream_write_string(f, ";\n");      Stream_write_string(f, ";\n");
1109      break;      break;
# Line 1113  Line 1111 
1111      assert(node->pn_arity == PN_UNARY);      assert(node->pn_arity == PN_UNARY);
1112      Stream_printf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
1113      if (node->pn_kid != NULL) {      if (node->pn_kid != NULL) {
1114        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, true);
1115      }      }
1116      Stream_write_string(f, ";\n");      Stream_write_string(f, ";\n");
1117      break;      break;
1118    case TOK_COLON:    case TOK_COLON:
1119      {
1120      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 ...  
     */  
1121      Stream_printf(f, "%*s", indent < 2? 0: indent - 2, "");      Stream_printf(f, "%*s", indent < 2? 0: indent - 2, "");
1122      print_string_atom(node->pn_atom, f);      print_string_atom(node->pn_atom, f);
1123      Stream_write_string(f, ":\n");      Stream_write_string(f, ":\n");
1124      /*      JSParseNode * labelled = node->pn_expr;
1125      ... use output_statement instead of instrument_statement.      if (labelled->pn_type == TOK_LEXICALSCOPE) {
1126      */        labelled = labelled->pn_expr;
1127      output_statement(node->pn_expr, f, indent, false);      }
1128        if (labelled->pn_type == TOK_LC) {
1129          /* labelled block */
1130          Stream_printf(f, "%*s", indent, "");
1131          Stream_write_string(f, "{\n");
1132          instrument_statement(labelled, f, indent + 2, false);
1133          Stream_printf(f, "%*s", indent, "");
1134          Stream_write_string(f, "}\n");
1135        }
1136        else {
1137          /*
1138          This one is tricky: can't output instrumentation between the label and the
1139          statement it's supposed to label, so use output_statement instead of
1140          instrument_statement.
1141          */
1142          output_statement(labelled, f, indent, false);
1143        }
1144      break;      break;
1145      }
1146    case TOK_LEXICALSCOPE:    case TOK_LEXICALSCOPE:
1147      /* let statement */      /* let statement */
1148      assert(node->pn_arity == PN_NAME);      assert(node->pn_arity == PN_NAME);
# Line 1173  Line 1185 
1185      case PN_LIST:      case PN_LIST:
1186        /* let definition */        /* let definition */
1187        Stream_printf(f, "%*s", indent, "");        Stream_printf(f, "%*s", indent, "");
1188        instrument_expression(node, f);        output_expression(node, f, false);
1189        Stream_write_string(f, ";\n");        Stream_write_string(f, ";\n");
1190        break;        break;
1191      default:      default:
# Line 1185  Line 1197 
1197      Stream_printf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
1198      Stream_write_string(f, "debugger;\n");      Stream_write_string(f, "debugger;\n");
1199      break;      break;
1200      case TOK_SEQ:
1201        /*
1202        This occurs with the statement:
1203        for (var a = b in c) {}
1204        */
1205        assert(node->pn_arity == PN_LIST);
1206        for (JSParseNode * p = node->pn_head; p != NULL; p = p->pn_next) {
1207          instrument_statement(p, f, indent, false);
1208        }
1209        break;
1210    default:    default:
1211      fatal_source(file_id, node->pn_pos.begin.lineno, "unsupported node type (%d)", node->pn_type);      fatal_source(file_id, node->pn_pos.begin.lineno, "unsupported node type (%d)", node->pn_type);
1212    }    }
# Line 1266  Line 1288 
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;
1291    lines = xmalloc(num_lines);    lines = (char *) xmalloc(num_lines);
1292    for (unsigned int i = 0; i < num_lines; i++) {    for (unsigned int i = 0; i < num_lines; i++) {
1293      lines[i] = 0;      lines[i] = 0;
1294    }    }
# Line 1579  Line 1601 
1601  };  };
1602    
1603  static int compare_strings(const void * p1, const void * p2) {  static int compare_strings(const void * p1, const void * p2) {
1604    return strcmp(p1, p2) == 0;    return strcmp((const char *) p1, (const char *) p2) == 0;
1605  }  }
1606    
1607  Coverage * Coverage_new(void) {  Coverage * Coverage_new(void) {
1608    Coverage * result = xmalloc(sizeof(Coverage));    Coverage * result = (Coverage *) xmalloc(sizeof(Coverage));
1609    result->coverage_table = JS_NewHashTable(1024, JS_HashString, compare_strings, NULL, NULL, NULL);    result->coverage_table = JS_NewHashTable(1024, JS_HashString, compare_strings, NULL, NULL, NULL);
1610    if (result->coverage_table == NULL) {    if (result->coverage_table == NULL) {
1611      fatal("cannot create hash table");      fatal("cannot create hash table");
# Line 1618  Line 1640 
1640  };  };
1641    
1642  static intN enumerator(JSHashEntry * entry, intN i, void * arg) {  static intN enumerator(JSHashEntry * entry, intN i, void * arg) {
1643    struct EnumeratorArg * enumerator_arg = arg;    struct EnumeratorArg * enumerator_arg = (struct EnumeratorArg *) arg;
1644    enumerator_arg->f(entry->value, i, enumerator_arg->p);    enumerator_arg->f((FileCoverage *) entry->value, i, enumerator_arg->p);
1645    return 0;    return 0;
1646  }  }
1647    
# Line 1652  Line 1674 
1674    }    }
1675    JSParseNode * root = js_ParseScript(context, global, &parse_context);    JSParseNode * root = js_ParseScript(context, global, &parse_context);
1676    free(parenthesized_json);    free(parenthesized_json);
1677    
1678      JSParseNode * semi = NULL;
1679      JSParseNode * object = NULL;
1680    
1681    if (root == NULL) {    if (root == NULL) {
1682      result = -1;      result = -1;
1683      goto done;      goto done;
# Line 1662  Line 1688 
1688      result = -1;      result = -1;
1689      goto done;      goto done;
1690    }    }
1691    JSParseNode * semi = root->pn_u.list.head;    semi = root->pn_u.list.head;
1692    
1693    /* the list must be TOK_SEMI and it must contain only one element */    /* the list must be TOK_SEMI and it must contain only one element */
1694    if (semi->pn_type != TOK_SEMI || semi->pn_next != NULL) {    if (semi->pn_type != TOK_SEMI || semi->pn_next != NULL) {
1695      result = -1;      result = -1;
1696      goto done;      goto done;
1697    }    }
1698    JSParseNode * parenthesized = semi->pn_kid;    object = semi->pn_kid;
   
   /* this must be a parenthesized expression */  
   if (parenthesized->pn_type != TOK_RP) {  
     result = -1;  
     goto done;  
   }  
   JSParseNode * object = parenthesized->pn_kid;  
1699    
1700    /* this must be an object literal */    /* this must be an object literal */
1701    if (object->pn_type != TOK_RC) {    if (object->pn_type != TOK_RC) {
# Line 1760  Line 1779 
1779      }      }
1780    
1781      /* look up the file in the coverage table */      /* look up the file in the coverage table */
1782      FileCoverage * file_coverage = JS_HashTableLookup(coverage->coverage_table, id_bytes);      FileCoverage * file_coverage = (FileCoverage *) JS_HashTableLookup(coverage->coverage_table, id_bytes);
1783      if (file_coverage == NULL) {      if (file_coverage == NULL) {
1784        /* not there: create a new one */        /* not there: create a new one */
1785        char * id = xstrdup(id_bytes);        char * id = xstrdup(id_bytes);
1786        file_coverage = xmalloc(sizeof(FileCoverage));        file_coverage = (FileCoverage *) xmalloc(sizeof(FileCoverage));
1787        file_coverage->id = id;        file_coverage->id = id;
1788        file_coverage->num_coverage_lines = array->pn_count;        file_coverage->num_coverage_lines = array->pn_count;
1789        file_coverage->coverage_lines = xnew(int, array->pn_count);        file_coverage->coverage_lines = xnew(int, array->pn_count);
# Line 1788  Line 1807 
1807    
1808        /* add to the hash table */        /* add to the hash table */
1809        JS_HashTableAdd(coverage->coverage_table, id, file_coverage);        JS_HashTableAdd(coverage->coverage_table, id, file_coverage);
1810        struct FileCoverageList * coverage_list = xmalloc(sizeof(struct FileCoverageList));        struct FileCoverageList * coverage_list = (FileCoverageList *) xmalloc(sizeof(struct FileCoverageList));
1811        coverage_list->file_coverage = file_coverage;        coverage_list->file_coverage = file_coverage;
1812        coverage_list->next = coverage->coverage_list;        coverage_list->next = coverage->coverage_list;
1813        coverage->coverage_list = coverage_list;        coverage->coverage_list = coverage_list;

Legend:
Removed from v.374  
changed lines
  Added in v.401

  ViewVC Help
Powered by ViewVC 1.1.24