/[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 378 by siliconforks, Tue Oct 28 05:31:03 2008 UTC trunk/instrument-js.cpp revision 402 by siliconforks, Tue Dec 9 09:47:43 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 304  Line 305 
305      assert(if_node->pn_arity == PN_TERNARY);      assert(if_node->pn_arity == PN_TERNARY);
306      p = if_node->pn_kid2;      p = if_node->pn_kid2;
307    }    }
308    assert(p->pn_arity == PN_UNARY);    switch (p->pn_arity) {
309    p = p->pn_kid;    case PN_UNARY:
   if (p->pn_type == TOK_YIELD) {  
     /* for generator expressions */  
310      p = p->pn_kid;      p = p->pn_kid;
311        if (p->pn_type == TOK_YIELD) {
312          /* for generator expressions */
313          p = p->pn_kid;
314        }
315        output_expression(p, f, false);
316        break;
317      case PN_LIST:
318        /*
319        When the array comprehension contains "if (0)", it will be optimized away and
320        the result will be an empty TOK_LC list.
321        */
322        assert(p->pn_type == TOK_LC);
323        assert(p->pn_head == NULL);
324        /* the "1" is arbitrary (since the list is empty) */
325        Stream_write_char(f, '1');
326        break;
327      default:
328        abort();
329        break;
330    }    }
331    
   instrument_expression(p, f);  
332    p = for_node;    p = for_node;
333    while (p->pn_type == TOK_FOR) {    while (p->pn_type == TOK_FOR) {
334      Stream_write_char(f, ' ');      Stream_write_char(f, ' ');
335      output_for_in(p, f);      output_for_in(p, f);
336      p = p->pn_right;      p = p->pn_right;
337    }    }
338    if (if_node) {    if (p->pn_type == TOK_LC) {
339        /* this is the optimized-away "if (0)" */
340        Stream_write_string(f, " if (0)");
341      }
342      else if (if_node) {
343      Stream_write_string(f, " if (");      Stream_write_string(f, " if (");
344      instrument_expression(if_node->pn_kid1, f);      output_expression(if_node->pn_kid1, f, false);
345      Stream_write_char(f, ')');      Stream_write_char(f, ')');
346    }    }
347  }  }
348    
 static void output_destructuring_expression(JSParseNode * node, Stream * f) {  
   switch (node->pn_type) {  
   case TOK_NAME:  
     assert(node->pn_arity == PN_NAME);  
     print_string_atom(node->pn_atom, f);  
     if (node->pn_expr != NULL) {  
       Stream_write_string(f, " = ");  
       instrument_expression(node->pn_expr, f);  
     }  
     break;  
   case TOK_RB:  
     Stream_write_char(f, '[');  
     for (JSParseNode * p = node->pn_head; p != NULL; p = p->pn_next) {  
       if (p != node->pn_head) {  
         Stream_write_string(f, ", ");  
       }  
       /* TOK_COMMA is a special case: a hole in the array */  
       if (p->pn_type != TOK_COMMA) {  
         output_destructuring_expression(p, f);  
       }  
     }  
     if (node->pn_extra == PNX_ENDCOMMA) {  
       Stream_write_char(f, ',');  
     }  
     Stream_write_char(f, ']');  
     break;  
   case TOK_RC:  
     Stream_write_char(f, '{');  
     for (JSParseNode * p = node->pn_head; p != NULL; p = p->pn_next) {  
       if (p != node->pn_head) {  
         Stream_write_string(f, ", ");  
       }  
       if (p->pn_type != TOK_COLON) {  
         fatal_source(file_id, p->pn_pos.begin.lineno, "unsupported node type (%d)", p->pn_type);  
       }  
       instrument_expression(p->pn_left, f);  
       Stream_write_string(f, ": ");  
       output_destructuring_expression(p->pn_right, f);  
     }  
     Stream_write_char(f, '}');  
     break;  
   case TOK_ASSIGN:  
     output_destructuring_expression(node->pn_left, f);  
     Stream_write_string(f, " = ");  
     instrument_expression(node->pn_right, f);  
     break;  
   default:  
     fatal_source(file_id, node->pn_pos.begin.lineno, "unsupported node type (%d)", node->pn_type);  
     break;  
   }  
 }  
   
349  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) {
350    assert(node->pn_type == TOK_FUNCTION);    assert(node->pn_type == TOK_FUNCTION);
351    assert(node->pn_arity == PN_FUNC);    assert(node->pn_arity == PN_FUNC);
# Line 418  Line 387 
387      if (param == NULL) {      if (param == NULL) {
388        destructuring = true;        destructuring = true;
389        JSParseNode * expression = NULL;        JSParseNode * expression = NULL;
390        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);
391        JSParseNode * semi = node->pn_body->pn_head;        JSParseNode * semi = node->pn_body->pn_head;
392        assert(semi->pn_type == TOK_SEMI);        assert(semi->pn_type == TOK_SEMI);
393        JSParseNode * comma = semi->pn_kid;        JSParseNode * comma = semi->pn_kid;
# Line 433  Line 402 
402          }          }
403        }        }
404        assert(expression != NULL);        assert(expression != NULL);
405        output_destructuring_expression(expression, f);        output_expression(expression, f, false);
406      }      }
407      else {      else {
408        print_string_atom(param, f);        print_string_atom(param, f);
# Line 445  Line 414 
414    /* function body */    /* function body */
415    if (function->flags & JSFUN_EXPR_CLOSURE) {    if (function->flags & JSFUN_EXPR_CLOSURE) {
416      /* expression closure - use output_statement instead of instrument_statement */      /* expression closure - use output_statement instead of instrument_statement */
417      if (node->pn_body->pn_type == TOK_BODY) {      if (node->pn_body->pn_type == TOK_SEQ) {
418        assert(node->pn_body->pn_arity == PN_LIST);        assert(node->pn_body->pn_arity == PN_LIST);
419        assert(node->pn_body->pn_count == 2);        assert(node->pn_body->pn_count == 2);
420        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 466  Line 435 
435      }      }
436    }    }
437    
438    Stream_write_string(f, "}\n");    Stream_write_char(f, '}');
439  }  }
440    
441  static void instrument_function_call(JSParseNode * node, Stream * f) {  static void instrument_function_call(JSParseNode * node, Stream * f) {
# Line 485  Line 454 
454        Stream_write_char(f, ')');        Stream_write_char(f, ')');
455        return;        return;
456      }      }
     else {  
       Stream_write_char(f, '(');  
       instrument_expression(function_node, f);  
       Stream_write_char(f, ')');  
     }  
   }  
   else {  
     instrument_expression(function_node, f);  
457    }    }
458      output_expression(function_node, f, false);
459    Stream_write_char(f, '(');    Stream_write_char(f, '(');
460    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) {
461      if (p != node->pn_head->pn_next) {      if (p != node->pn_head->pn_next) {
462        Stream_write_string(f, ", ");        Stream_write_string(f, ", ");
463      }      }
464      instrument_expression(p, f);      output_expression(p, f, false);
465    }    }
466    Stream_write_char(f, ')');    Stream_write_char(f, ')');
467  }  }
# Line 510  Line 472 
472      if (p != list->pn_head) {      if (p != list->pn_head) {
473        Stream_write_string(f, ", ");        Stream_write_string(f, ", ");
474      }      }
475      output_destructuring_expression(p, f);      output_expression(p, f, false);
476    }    }
477  }  }
478    
# Line 527  Line 489 
489  TOK_INSTANCEOF  binary  TOK_INSTANCEOF  binary
490  TOK_IN          binary  TOK_IN          binary
491  */  */
492  static void instrument_expression(JSParseNode * node, Stream * f) {  static void output_expression(JSParseNode * node, Stream * f, bool parenthesize_object_literals) {
493    switch (node->pn_type) {    switch (node->pn_type) {
494    case TOK_FUNCTION:    case TOK_FUNCTION:
495        Stream_write_char(f, '(');
496      instrument_function(node, f, 0, FUNCTION_NORMAL);      instrument_function(node, f, 0, FUNCTION_NORMAL);
497        Stream_write_char(f, ')');
498      break;      break;
499    case TOK_COMMA:    case TOK_COMMA:
500      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) {
501        if (p != node->pn_head) {        if (p != node->pn_head) {
502          Stream_write_string(f, ", ");          Stream_write_string(f, ", ");
503        }        }
504        instrument_expression(p, f);        output_expression(p, f, parenthesize_object_literals);
505      }      }
506      break;      break;
507    case TOK_ASSIGN:    case TOK_ASSIGN:
508      switch (node->pn_left->pn_type) {      output_expression(node->pn_left, f, parenthesize_object_literals);
     case TOK_RB:  
       output_destructuring_expression(node->pn_left, f);  
       break;  
     case TOK_RC:  
       Stream_write_char(f, '(');  
       output_destructuring_expression(node->pn_left, f);  
       Stream_write_char(f, ')');  
       break;  
     default:  
       instrument_expression(node->pn_left, f);  
       break;  
     }  
509      Stream_write_char(f, ' ');      Stream_write_char(f, ' ');
510      switch (node->pn_op) {      switch (node->pn_op) {
511      case JSOP_ADD:      case JSOP_ADD:
# Line 574  Line 526 
526        break;        break;
527      }      }
528      Stream_write_string(f, "= ");      Stream_write_string(f, "= ");
529      instrument_expression(node->pn_right, f);      output_expression(node->pn_right, f, false);
530      break;      break;
531    case TOK_HOOK:    case TOK_HOOK:
532      instrument_expression(node->pn_kid1, f);      output_expression(node->pn_kid1, f, parenthesize_object_literals);
533      Stream_write_string(f, "? ");      Stream_write_string(f, "? ");
534      instrument_expression(node->pn_kid2, f);      output_expression(node->pn_kid2, f, false);
535      Stream_write_string(f, ": ");      Stream_write_string(f, ": ");
536      instrument_expression(node->pn_kid3, f);      output_expression(node->pn_kid3, f, false);
537      break;      break;
538    case TOK_OR:    case TOK_OR:
539    case TOK_AND:    case TOK_AND:
# Line 597  Line 549 
549    case TOK_DIVOP:    case TOK_DIVOP:
550      switch (node->pn_arity) {      switch (node->pn_arity) {
551      case PN_BINARY:      case PN_BINARY:
552        instrument_expression(node->pn_left, f);        output_expression(node->pn_left, f, parenthesize_object_literals);
553        Stream_printf(f, " %s ", get_op(node->pn_op));        Stream_printf(f, " %s ", get_op(node->pn_op));
554        instrument_expression(node->pn_right, f);        output_expression(node->pn_right, f, false);
555        break;        break;
556      case PN_LIST:      case PN_LIST:
557        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) {
558          if (p != node->pn_head) {          if (p == node->pn_head) {
559              output_expression(p, f, parenthesize_object_literals);
560            }
561            else {
562            Stream_printf(f, " %s ", get_op(node->pn_op));            Stream_printf(f, " %s ", get_op(node->pn_op));
563              output_expression(p, f, false);
564          }          }
         instrument_expression(p, f);  
565        }        }
566        break;        break;
567      default:      default:
# Line 616  Line 571 
571    case TOK_UNARYOP:    case TOK_UNARYOP:
572      switch (node->pn_op) {      switch (node->pn_op) {
573      case JSOP_NEG:      case JSOP_NEG:
574        Stream_write_char(f, '-');        Stream_write_string(f, "- ");
575        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, false);
576        break;        break;
577      case JSOP_POS:      case JSOP_POS:
578        Stream_write_char(f, '+');        Stream_write_string(f, "+ ");
579        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, false);
580        break;        break;
581      case JSOP_NOT:      case JSOP_NOT:
582        Stream_write_char(f, '!');        Stream_write_string(f, "! ");
583        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, false);
584        break;        break;
585      case JSOP_BITNOT:      case JSOP_BITNOT:
586        Stream_write_char(f, '~');        Stream_write_string(f, "~ ");
587        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, false);
588        break;        break;
589      case JSOP_TYPEOF:      case JSOP_TYPEOF:
590        Stream_write_string(f, "typeof ");        Stream_write_string(f, "typeof ");
591        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, false);
592        break;        break;
593      case JSOP_VOID:      case JSOP_VOID:
594        Stream_write_string(f, "void ");        Stream_write_string(f, "void ");
595        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, false);
596        break;        break;
597      default:      default:
598        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 654  Line 609 
609      case JSOP_INCPROP:      case JSOP_INCPROP:
610      case JSOP_INCELEM:      case JSOP_INCELEM:
611        Stream_write_string(f, "++");        Stream_write_string(f, "++");
612        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, false);
613        break;        break;
614      case JSOP_DECNAME:      case JSOP_DECNAME:
615      case JSOP_DECPROP:      case JSOP_DECPROP:
616      case JSOP_DECELEM:      case JSOP_DECELEM:
617        Stream_write_string(f, "--");        Stream_write_string(f, "--");
618        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, false);
619        break;        break;
620      case JSOP_NAMEINC:      case JSOP_NAMEINC:
621      case JSOP_PROPINC:      case JSOP_PROPINC:
622      case JSOP_ELEMINC:      case JSOP_ELEMINC:
623        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, parenthesize_object_literals);
624        Stream_write_string(f, "++");        Stream_write_string(f, "++");
625        break;        break;
626      case JSOP_NAMEDEC:      case JSOP_NAMEDEC:
627      case JSOP_PROPDEC:      case JSOP_PROPDEC:
628      case JSOP_ELEMDEC:      case JSOP_ELEMDEC:
629        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, parenthesize_object_literals);
630        Stream_write_string(f, "--");        Stream_write_string(f, "--");
631        break;        break;
632      default:      default:
# Line 685  Line 640 
640      break;      break;
641    case TOK_DELETE:    case TOK_DELETE:
642      Stream_write_string(f, "delete ");      Stream_write_string(f, "delete ");
643      instrument_expression(node->pn_kid, f);      output_expression(node->pn_kid, f, false);
644      break;      break;
645    case TOK_DOT:    case TOK_DOT:
646      /* numeric literals must be parenthesized */      /* numeric literals must be parenthesized */
647      switch (node->pn_expr->pn_type) {      switch (node->pn_expr->pn_type) {
648      case TOK_NUMBER:      case TOK_NUMBER:
649        Stream_write_char(f, '(');        Stream_write_char(f, '(');
650        instrument_expression(node->pn_expr, f);        output_expression(node->pn_expr, f, false);
651        Stream_write_char(f, ')');        Stream_write_char(f, ')');
652        break;        break;
653      default:      default:
654        instrument_expression(node->pn_expr, f);        output_expression(node->pn_expr, f, true);
655        break;        break;
656      }      }
657      /*      /*
# Line 732  Line 687 
687      }      }
688      break;      break;
689    case TOK_LB:    case TOK_LB:
690      instrument_expression(node->pn_left, f);      output_expression(node->pn_left, f, false);
691      Stream_write_char(f, '[');      Stream_write_char(f, '[');
692      instrument_expression(node->pn_right, f);      output_expression(node->pn_right, f, false);
693      Stream_write_char(f, ']');      Stream_write_char(f, ']');
694      break;      break;
695    case TOK_LP:    case TOK_LP:
# Line 748  Line 703 
703        }        }
704        /* TOK_COMMA is a special case: a hole in the array */        /* TOK_COMMA is a special case: a hole in the array */
705        if (p->pn_type != TOK_COMMA) {        if (p->pn_type != TOK_COMMA) {
706          instrument_expression(p, f);          output_expression(p, f, false);
707        }        }
708      }      }
709      if (node->pn_extra == PNX_ENDCOMMA) {      if (node->pn_extra == PNX_ENDCOMMA) {
# Line 757  Line 712 
712      Stream_write_char(f, ']');      Stream_write_char(f, ']');
713      break;      break;
714    case TOK_RC:    case TOK_RC:
715      Stream_write_char(f, '(');      if (parenthesize_object_literals) {
716          Stream_write_char(f, '(');
717        }
718      Stream_write_char(f, '{');      Stream_write_char(f, '{');
719      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) {
720        if (p->pn_type != TOK_COLON) {        if (p->pn_type != TOK_COLON) {
# Line 777  Line 734 
734          else {          else {
735            Stream_write_string(f, "set ");            Stream_write_string(f, "set ");
736          }          }
737          instrument_expression(p->pn_left, f);          output_expression(p->pn_left, f, false);
738            Stream_write_char(f, ' ');
739          if (p->pn_right->pn_type != TOK_FUNCTION) {          if (p->pn_right->pn_type != TOK_FUNCTION) {
740            fatal_source(file_id, p->pn_pos.begin.lineno, "expected function");            fatal_source(file_id, p->pn_pos.begin.lineno, "expected function");
741          }          }
742          instrument_function(p->pn_right, f, 0, FUNCTION_GETTER_OR_SETTER);          instrument_function(p->pn_right, f, 0, FUNCTION_GETTER_OR_SETTER);
743          break;          break;
744        default:        default:
745          instrument_expression(p->pn_left, f);          output_expression(p->pn_left, f, false);
746          Stream_write_string(f, ": ");          Stream_write_string(f, ": ");
747          instrument_expression(p->pn_right, f);          output_expression(p->pn_right, f, false);
748          break;          break;
749        }        }
750      }      }
751      Stream_write_char(f, '}');      Stream_write_char(f, '}');
752      Stream_write_char(f, ')');      if (parenthesize_object_literals) {
753          Stream_write_char(f, ')');
754        }
755      break;      break;
756    case TOK_RP:    case TOK_RP:
757      Stream_write_char(f, '(');      Stream_write_char(f, '(');
758      instrument_expression(node->pn_kid, f);      output_expression(node->pn_kid, f, false);
759      Stream_write_char(f, ')');      Stream_write_char(f, ')');
760      break;      break;
761    case TOK_NAME:    case TOK_NAME:
762      print_string_atom(node->pn_atom, f);      print_string_atom(node->pn_atom, f);
763        if (node->pn_expr != NULL) {
764          Stream_write_string(f, " = ");
765          output_expression(node->pn_expr, f, false);
766        }
767      break;      break;
768    case TOK_STRING:    case TOK_STRING:
769      print_quoted_string_atom(node->pn_atom, f);      print_quoted_string_atom(node->pn_atom, f);
# Line 821  Line 785 
785      To keep the output simple, special-case zero.      To keep the output simple, special-case zero.
786      */      */
787      if (node->pn_dval == 0.0) {      if (node->pn_dval == 0.0) {
788        Stream_write_string(f, "0");        if (signbit(node->pn_dval)) {
789            Stream_write_string(f, "-0");
790          }
791          else {
792            Stream_write_string(f, "0");
793          }
794        }
795        else if (node->pn_dval == INFINITY) {
796          Stream_write_string(f, "Number.POSITIVE_INFINITY");
797        }
798        else if (node->pn_dval == -INFINITY) {
799          Stream_write_string(f, "Number.NEGATIVE_INFINITY");
800        }
801        else if (isnan(node->pn_dval)) {
802          Stream_write_string(f, "Number.NaN");
803      }      }
804      else {      else {
805        Stream_printf(f, "%.15g", node->pn_dval);        Stream_printf(f, "%.15g", node->pn_dval);
# Line 847  Line 825 
825      }      }
826      break;      break;
827    case TOK_INSTANCEOF:    case TOK_INSTANCEOF:
828      instrument_expression(node->pn_left, f);      output_expression(node->pn_left, f, parenthesize_object_literals);
829      Stream_write_string(f, " instanceof ");      Stream_write_string(f, " instanceof ");
830      instrument_expression(node->pn_right, f);      output_expression(node->pn_right, f, false);
831      break;      break;
832    case TOK_IN:    case TOK_IN:
833      instrument_expression(node->pn_left, f);      output_expression(node->pn_left, f, false);
834      Stream_write_string(f, " in ");      Stream_write_string(f, " in ");
835      instrument_expression(node->pn_right, f);      output_expression(node->pn_right, f, false);
836      break;      break;
837    case TOK_LEXICALSCOPE:    case TOK_LEXICALSCOPE:
838      assert(node->pn_arity == PN_NAME);      assert(node->pn_arity == PN_NAME);
# Line 865  Line 843 
843      assert(node->pn_expr->pn_left->pn_arity == PN_LIST);      assert(node->pn_expr->pn_left->pn_arity == PN_LIST);
844      instrument_declarations(node->pn_expr->pn_left, f);      instrument_declarations(node->pn_expr->pn_left, f);
845      Stream_write_string(f, ") ");      Stream_write_string(f, ") ");
846      instrument_expression(node->pn_expr->pn_right, f);      output_expression(node->pn_expr->pn_right, f, true);
847      break;      break;
848    case TOK_YIELD:    case TOK_YIELD:
849      assert(node->pn_arity == PN_UNARY);      assert(node->pn_arity == PN_UNARY);
850      Stream_write_string(f, "yield");      Stream_write_string(f, "yield");
851      if (node->pn_kid != NULL) {      if (node->pn_kid != NULL) {
852        Stream_write_char(f, ' ');        Stream_write_char(f, ' ');
853        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, true);
854      }      }
855      break;      break;
856    case TOK_ARRAYCOMP:    case TOK_ARRAYCOMP:
# Line 914  Line 892 
892    switch (node->pn_type) {    switch (node->pn_type) {
893    case TOK_FUNCTION:    case TOK_FUNCTION:
894      instrument_function(node, f, indent, FUNCTION_NORMAL);      instrument_function(node, f, indent, FUNCTION_NORMAL);
895        Stream_write_char(f, '\n');
896      break;      break;
897    case TOK_LC:    case TOK_LC:
898      assert(node->pn_arity == PN_LIST);      assert(node->pn_arity == PN_LIST);
# Line 944  Line 923 
923    
924      Stream_printf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
925      Stream_write_string(f, "if (");      Stream_write_string(f, "if (");
926      instrument_expression(node->pn_kid1, f);      output_expression(node->pn_kid1, f, false);
927      Stream_write_string(f, ") {\n");      Stream_write_string(f, ") {\n");
928      if (is_jscoverage_if && node->pn_kid3) {      if (is_jscoverage_if && node->pn_kid3) {
929        uint16_t else_start = node->pn_kid3->pn_pos.begin.lineno;        uint16_t else_start = node->pn_kid3->pn_pos.begin.lineno;
# Line 981  Line 960 
960      assert(node->pn_arity == PN_BINARY);      assert(node->pn_arity == PN_BINARY);
961      Stream_printf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
962      Stream_write_string(f, "switch (");      Stream_write_string(f, "switch (");
963      instrument_expression(node->pn_left, f);      output_expression(node->pn_left, f, false);
964      Stream_write_string(f, ") {\n");      Stream_write_string(f, ") {\n");
965      {      {
966        JSParseNode * list = node->pn_right;        JSParseNode * list = node->pn_right;
# Line 993  Line 972 
972          switch (p->pn_type) {          switch (p->pn_type) {
973          case TOK_CASE:          case TOK_CASE:
974            Stream_write_string(f, "case ");            Stream_write_string(f, "case ");
975            instrument_expression(p->pn_left, f);            output_expression(p->pn_left, f, false);
976            Stream_write_string(f, ":\n");            Stream_write_string(f, ":\n");
977            break;            break;
978          case TOK_DEFAULT:          case TOK_DEFAULT:
# Line 1017  Line 996 
996      assert(node->pn_arity == PN_BINARY);      assert(node->pn_arity == PN_BINARY);
997      Stream_printf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
998      Stream_write_string(f, "while (");      Stream_write_string(f, "while (");
999      instrument_expression(node->pn_left, f);      output_expression(node->pn_left, f, false);
1000      Stream_write_string(f, ") {\n");      Stream_write_string(f, ") {\n");
1001      instrument_statement(node->pn_right, f, indent + 2, false);      instrument_statement(node->pn_right, f, indent + 2, false);
1002      Stream_write_string(f, "}\n");      Stream_write_string(f, "}\n");
# Line 1030  Line 1009 
1009      Stream_write_string(f, "}\n");      Stream_write_string(f, "}\n");
1010      Stream_printf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
1011      Stream_write_string(f, "while (");      Stream_write_string(f, "while (");
1012      instrument_expression(node->pn_right, f);      output_expression(node->pn_right, f, false);
1013      Stream_write_string(f, ");\n");      Stream_write_string(f, ");\n");
1014      break;      break;
1015    case TOK_FOR:    case TOK_FOR:
# Line 1042  Line 1021 
1021        assert(node->pn_left->pn_arity == PN_BINARY);        assert(node->pn_left->pn_arity == PN_BINARY);
1022        output_for_in(node, f);        output_for_in(node, f);
1023        break;        break;
1024      case TOK_RESERVED:      case TOK_FORHEAD:
1025        /* for (;;) */        /* for (;;) */
1026        assert(node->pn_left->pn_arity == PN_TERNARY);        assert(node->pn_left->pn_arity == PN_TERNARY);
1027        Stream_write_string(f, "for (");        Stream_write_string(f, "for (");
1028        if (node->pn_left->pn_kid1) {        if (node->pn_left->pn_kid1) {
1029          instrument_expression(node->pn_left->pn_kid1, f);          output_expression(node->pn_left->pn_kid1, f, false);
1030        }        }
1031        Stream_write_string(f, ";");        Stream_write_string(f, ";");
1032        if (node->pn_left->pn_kid2) {        if (node->pn_left->pn_kid2) {
1033          Stream_write_char(f, ' ');          Stream_write_char(f, ' ');
1034          instrument_expression(node->pn_left->pn_kid2, f);          output_expression(node->pn_left->pn_kid2, f, false);
1035        }        }
1036        Stream_write_string(f, ";");        Stream_write_string(f, ";");
1037        if (node->pn_left->pn_kid3) {        if (node->pn_left->pn_kid3) {
1038          Stream_write_char(f, ' ');          Stream_write_char(f, ' ');
1039          instrument_expression(node->pn_left->pn_kid3, f);          output_expression(node->pn_left->pn_kid3, f, false);
1040        }        }
1041        Stream_write_char(f, ')');        Stream_write_char(f, ')');
1042        break;        break;
# Line 1073  Line 1052 
1052      assert(node->pn_arity == PN_UNARY);      assert(node->pn_arity == PN_UNARY);
1053      Stream_printf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
1054      Stream_write_string(f, "throw ");      Stream_write_string(f, "throw ");
1055      instrument_expression(node->pn_u.unary.kid, f);      output_expression(node->pn_u.unary.kid, f, false);
1056      Stream_write_string(f, ";\n");      Stream_write_string(f, ";\n");
1057      break;      break;
1058    case TOK_TRY:    case TOK_TRY:
# Line 1086  Line 1065 
1065        assert(node->pn_kid2->pn_type == TOK_RESERVED);        assert(node->pn_kid2->pn_type == TOK_RESERVED);
1066        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) {
1067          assert(scope->pn_type == TOK_LEXICALSCOPE);          assert(scope->pn_type == TOK_LEXICALSCOPE);
1068          JSParseNode * catch = scope->pn_expr;          JSParseNode * catch_node = scope->pn_expr;
1069          assert(catch->pn_type == TOK_CATCH);          assert(catch_node->pn_type == TOK_CATCH);
1070          Stream_printf(f, "%*s", indent, "");          Stream_printf(f, "%*s", indent, "");
1071          Stream_write_string(f, "catch (");          Stream_write_string(f, "catch (");
1072          output_destructuring_expression(catch->pn_kid1, f);          output_expression(catch_node->pn_kid1, f, false);
1073          if (catch->pn_kid2) {          if (catch_node->pn_kid2) {
1074            Stream_write_string(f, " if ");            Stream_write_string(f, " if ");
1075            instrument_expression(catch->pn_kid2, f);            output_expression(catch_node->pn_kid2, f, false);
1076          }          }
1077          Stream_write_string(f, ") {\n");          Stream_write_string(f, ") {\n");
1078          instrument_statement(catch->pn_kid3, f, indent + 2, false);          instrument_statement(catch_node->pn_kid3, f, indent + 2, false);
1079          Stream_printf(f, "%*s", indent, "");          Stream_printf(f, "%*s", indent, "");
1080          Stream_write_string(f, "}\n");          Stream_write_string(f, "}\n");
1081        }        }
# Line 1117  Line 1096 
1096      assert(node->pn_arity == PN_NAME || node->pn_arity == PN_NULLARY);      assert(node->pn_arity == PN_NAME || node->pn_arity == PN_NULLARY);
1097      Stream_printf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
1098      Stream_write_string(f, node->pn_type == TOK_BREAK? "break": "continue");      Stream_write_string(f, node->pn_type == TOK_BREAK? "break": "continue");
1099      JSAtom * atom = node->pn_u.name.atom;      if (node->pn_atom != NULL) {
     if (atom != NULL) {  
1100        Stream_write_char(f, ' ');        Stream_write_char(f, ' ');
1101        print_string_atom(node->pn_atom, f);        print_string_atom(node->pn_atom, f);
1102      }      }
# Line 1128  Line 1106 
1106      assert(node->pn_arity == PN_BINARY);      assert(node->pn_arity == PN_BINARY);
1107      Stream_printf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
1108      Stream_write_string(f, "with (");      Stream_write_string(f, "with (");
1109      instrument_expression(node->pn_left, f);      output_expression(node->pn_left, f, false);
1110      Stream_write_string(f, ") {\n");      Stream_write_string(f, ") {\n");
1111      instrument_statement(node->pn_right, f, indent + 2, false);      instrument_statement(node->pn_right, f, indent + 2, false);
1112      Stream_printf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
# Line 1136  Line 1114 
1114      break;      break;
1115    case TOK_VAR:    case TOK_VAR:
1116      Stream_printf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
1117      instrument_expression(node, f);      output_expression(node, f, false);
1118      Stream_write_string(f, ";\n");      Stream_write_string(f, ";\n");
1119      break;      break;
1120    case TOK_RETURN:    case TOK_RETURN:
# Line 1145  Line 1123 
1123      Stream_write_string(f, "return");      Stream_write_string(f, "return");
1124      if (node->pn_kid != NULL) {      if (node->pn_kid != NULL) {
1125        Stream_write_char(f, ' ');        Stream_write_char(f, ' ');
1126        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, true);
1127      }      }
1128      Stream_write_string(f, ";\n");      Stream_write_string(f, ";\n");
1129      break;      break;
# Line 1153  Line 1131 
1131      assert(node->pn_arity == PN_UNARY);      assert(node->pn_arity == PN_UNARY);
1132      Stream_printf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
1133      if (node->pn_kid != NULL) {      if (node->pn_kid != NULL) {
1134        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, true);
1135      }      }
1136      Stream_write_string(f, ";\n");      Stream_write_string(f, ";\n");
1137      break;      break;
# Line 1227  Line 1205 
1205      case PN_LIST:      case PN_LIST:
1206        /* let definition */        /* let definition */
1207        Stream_printf(f, "%*s", indent, "");        Stream_printf(f, "%*s", indent, "");
1208        instrument_expression(node, f);        output_expression(node, f, false);
1209        Stream_write_string(f, ";\n");        Stream_write_string(f, ";\n");
1210        break;        break;
1211      default:      default:
# Line 1239  Line 1217 
1217      Stream_printf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
1218      Stream_write_string(f, "debugger;\n");      Stream_write_string(f, "debugger;\n");
1219      break;      break;
1220      case TOK_SEQ:
1221        /*
1222        This occurs with the statement:
1223        for (var a = b in c) {}
1224        */
1225        assert(node->pn_arity == PN_LIST);
1226        for (JSParseNode * p = node->pn_head; p != NULL; p = p->pn_next) {
1227          instrument_statement(p, f, indent, false);
1228        }
1229        break;
1230    default:    default:
1231      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);
1232    }    }
# Line 1320  Line 1308 
1308    }    }
1309    JS_SetErrorReporter(context, old_error_reporter);    JS_SetErrorReporter(context, old_error_reporter);
1310    num_lines = node->pn_pos.end.lineno;    num_lines = node->pn_pos.end.lineno;
1311    lines = xmalloc(num_lines);    lines = (char *) xmalloc(num_lines);
1312    for (unsigned int i = 0; i < num_lines; i++) {    for (unsigned int i = 0; i < num_lines; i++) {
1313      lines[i] = 0;      lines[i] = 0;
1314    }    }
# Line 1633  Line 1621 
1621  };  };
1622    
1623  static int compare_strings(const void * p1, const void * p2) {  static int compare_strings(const void * p1, const void * p2) {
1624    return strcmp(p1, p2) == 0;    return strcmp((const char *) p1, (const char *) p2) == 0;
1625  }  }
1626    
1627  Coverage * Coverage_new(void) {  Coverage * Coverage_new(void) {
1628    Coverage * result = xmalloc(sizeof(Coverage));    Coverage * result = (Coverage *) xmalloc(sizeof(Coverage));
1629    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);
1630    if (result->coverage_table == NULL) {    if (result->coverage_table == NULL) {
1631      fatal("cannot create hash table");      fatal("cannot create hash table");
# Line 1672  Line 1660 
1660  };  };
1661    
1662  static intN enumerator(JSHashEntry * entry, intN i, void * arg) {  static intN enumerator(JSHashEntry * entry, intN i, void * arg) {
1663    struct EnumeratorArg * enumerator_arg = arg;    struct EnumeratorArg * enumerator_arg = (struct EnumeratorArg *) arg;
1664    enumerator_arg->f(entry->value, i, enumerator_arg->p);    enumerator_arg->f((FileCoverage *) entry->value, i, enumerator_arg->p);
1665    return 0;    return 0;
1666  }  }
1667    
# Line 1706  Line 1694 
1694    }    }
1695    JSParseNode * root = js_ParseScript(context, global, &parse_context);    JSParseNode * root = js_ParseScript(context, global, &parse_context);
1696    free(parenthesized_json);    free(parenthesized_json);
1697    
1698      JSParseNode * semi = NULL;
1699      JSParseNode * object = NULL;
1700    
1701    if (root == NULL) {    if (root == NULL) {
1702      result = -1;      result = -1;
1703      goto done;      goto done;
# Line 1716  Line 1708 
1708      result = -1;      result = -1;
1709      goto done;      goto done;
1710    }    }
1711    JSParseNode * semi = root->pn_u.list.head;    semi = root->pn_u.list.head;
1712    
1713    /* 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 */
1714    if (semi->pn_type != TOK_SEMI || semi->pn_next != NULL) {    if (semi->pn_type != TOK_SEMI || semi->pn_next != NULL) {
1715      result = -1;      result = -1;
1716      goto done;      goto done;
1717    }    }
1718    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;  
1719    
1720    /* this must be an object literal */    /* this must be an object literal */
1721    if (object->pn_type != TOK_RC) {    if (object->pn_type != TOK_RC) {
# Line 1814  Line 1799 
1799      }      }
1800    
1801      /* look up the file in the coverage table */      /* look up the file in the coverage table */
1802      FileCoverage * file_coverage = JS_HashTableLookup(coverage->coverage_table, id_bytes);      FileCoverage * file_coverage = (FileCoverage *) JS_HashTableLookup(coverage->coverage_table, id_bytes);
1803      if (file_coverage == NULL) {      if (file_coverage == NULL) {
1804        /* not there: create a new one */        /* not there: create a new one */
1805        char * id = xstrdup(id_bytes);        char * id = xstrdup(id_bytes);
1806        file_coverage = xmalloc(sizeof(FileCoverage));        file_coverage = (FileCoverage *) xmalloc(sizeof(FileCoverage));
1807        file_coverage->id = id;        file_coverage->id = id;
1808        file_coverage->num_coverage_lines = array->pn_count;        file_coverage->num_coverage_lines = array->pn_count;
1809        file_coverage->coverage_lines = xnew(int, array->pn_count);        file_coverage->coverage_lines = xnew(int, array->pn_count);
# Line 1842  Line 1827 
1827    
1828        /* add to the hash table */        /* add to the hash table */
1829        JS_HashTableAdd(coverage->coverage_table, id, file_coverage);        JS_HashTableAdd(coverage->coverage_table, id, file_coverage);
1830        struct FileCoverageList * coverage_list = xmalloc(sizeof(struct FileCoverageList));        struct FileCoverageList * coverage_list = (FileCoverageList *) xmalloc(sizeof(struct FileCoverageList));
1831        coverage_list->file_coverage = file_coverage;        coverage_list->file_coverage = file_coverage;
1832        coverage_list->next = coverage->coverage_list;        coverage_list->next = coverage->coverage_list;
1833        coverage->coverage_list = coverage_list;        coverage->coverage_list = coverage_list;

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

  ViewVC Help
Powered by ViewVC 1.1.24