/[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 369 by siliconforks, Mon Oct 27 20:33:57 2008 UTC revision 380 by siliconforks, Wed Oct 29 00:10:22 2008 UTC
# Line 77  Line 77 
77    
78    char * end;    char * end;
79    js_version = (JSVersion) strtol(version, &end, 10);    js_version = (JSVersion) strtol(version, &end, 10);
80    if (end - version != strlen(version)) {    if ((size_t) (end - version) != strlen(version)) {
81      fatal("invalid version: %s", version);      fatal("invalid version: %s", version);
82    }    }
83  }  }
# Line 267  Line 267 
267    }    }
268  }  }
269    
270  static void instrument_expression(JSParseNode * node, Stream * f);  static void output_expression(JSParseNode * node, Stream * f, bool parenthesize_object_literals);
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);  static void output_statement(JSParseNode * node, Stream * f, int indent, bool is_jscoverage_if);
273    
# Line 284  Line 284 
284      Stream_write_string(f, "each ");      Stream_write_string(f, "each ");
285    }    }
286    Stream_write_char(f, '(');    Stream_write_char(f, '(');
287    instrument_expression(node->pn_left, f);    output_expression(node->pn_left, f, false);
288    Stream_write_char(f, ')');    Stream_write_char(f, ')');
289  }  }
290    
# Line 311  Line 311 
311      p = p->pn_kid;      p = p->pn_kid;
312    }    }
313    
314    instrument_expression(p, f);    output_expression(p, f, false);
315    p = for_node;    p = for_node;
316    while (p->pn_type == TOK_FOR) {    while (p->pn_type == TOK_FOR) {
317      Stream_write_char(f, ' ');      Stream_write_char(f, ' ');
# Line 320  Line 320 
320    }    }
321    if (if_node) {    if (if_node) {
322      Stream_write_string(f, " if (");      Stream_write_string(f, " if (");
323      instrument_expression(if_node->pn_kid1, f);      output_expression(if_node->pn_kid1, f, false);
324      Stream_write_char(f, ')');      Stream_write_char(f, ')');
325    }    }
326  }  }
# Line 335  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 348  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 358  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      if (param == NULL) {      if (param == NULL) {
367        fatal("unsupported parameter type for function: %s", file_id);        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          output_expression(expression, f, false);
385        }
386        else {
387          print_string_atom(param, f);
388      }      }
     print_string_atom(param, f);  
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    if (function->flags & JSFUN_EXPR_CLOSURE) {    if (function->flags & JSFUN_EXPR_CLOSURE) {
395      /* expression closure */      /* expression closure - use output_statement instead of instrument_statement */
396      output_statement(node->pn_body, f, indent + 2, false);      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 {    else {
406      instrument_statement(node->pn_body, f, indent + 2, false);      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_char(f, '}');
418  }  }
419    
420  static void instrument_function_call(JSParseNode * node, Stream * f) {  static void instrument_function_call(JSParseNode * node, Stream * f) {
# Line 399  Line 433 
433        Stream_write_char(f, ')');        Stream_write_char(f, ')');
434        return;        return;
435      }      }
     else {  
       Stream_write_char(f, '(');  
       instrument_expression(function_node, f);  
       Stream_write_char(f, ')');  
     }  
   }  
   else {  
     instrument_expression(function_node, f);  
436    }    }
437      output_expression(function_node, f, false);
438    Stream_write_char(f, '(');    Stream_write_char(f, '(');
439    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) {
440      if (p != node->pn_head->pn_next) {      if (p != node->pn_head->pn_next) {
441        Stream_write_string(f, ", ");        Stream_write_string(f, ", ");
442      }      }
443      instrument_expression(p, f);      output_expression(p, f, false);
444    }    }
445    Stream_write_char(f, ')');    Stream_write_char(f, ')');
446  }  }
# Line 421  Line 448 
448  static void instrument_declarations(JSParseNode * list, Stream * f) {  static void instrument_declarations(JSParseNode * list, Stream * f) {
449    assert(list->pn_arity == PN_LIST);    assert(list->pn_arity == PN_LIST);
450    for (JSParseNode * p = list->pn_head; p != NULL; p = p->pn_next) {    for (JSParseNode * p = list->pn_head; p != NULL; p = p->pn_next) {
451      switch (p->pn_type) {      if (p != list->pn_head) {
452      case TOK_NAME:        Stream_write_string(f, ", ");
       assert(p->pn_arity == PN_NAME);  
       if (p != list->pn_head) {  
         Stream_write_string(f, ", ");  
       }  
       print_string_atom(p->pn_atom, f);  
       if (p->pn_expr != NULL) {  
         Stream_write_string(f, " = ");  
         instrument_expression(p->pn_expr, f);  
       }  
       break;  
     case TOK_ASSIGN:  
     case TOK_RB:  
     case TOK_RC:  
       /* destructuring */  
       instrument_expression(p, f);  
       break;  
     default:  
       abort();  
       break;  
453      }      }
454        output_expression(p, f, false);
455    }    }
456  }  }
457    
# Line 459  Line 468 
468  TOK_INSTANCEOF  binary  TOK_INSTANCEOF  binary
469  TOK_IN          binary  TOK_IN          binary
470  */  */
471  static void instrument_expression(JSParseNode * node, Stream * f) {  static void output_expression(JSParseNode * node, Stream * f, bool parenthesize_object_literals) {
472    switch (node->pn_type) {    switch (node->pn_type) {
473    case TOK_FUNCTION:    case TOK_FUNCTION:
474        Stream_write_char(f, '(');
475      instrument_function(node, f, 0, FUNCTION_NORMAL);      instrument_function(node, f, 0, FUNCTION_NORMAL);
476        Stream_write_char(f, ')');
477      break;      break;
478    case TOK_COMMA:    case TOK_COMMA:
479      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) {
480        if (p != node->pn_head) {        if (p != node->pn_head) {
481          Stream_write_string(f, ", ");          Stream_write_string(f, ", ");
482        }        }
483        instrument_expression(p, f);        output_expression(p, f, parenthesize_object_literals);
484      }      }
485      break;      break;
486    case TOK_ASSIGN:    case TOK_ASSIGN:
487      instrument_expression(node->pn_left, f);      output_expression(node->pn_left, f, parenthesize_object_literals);
488      Stream_write_char(f, ' ');      Stream_write_char(f, ' ');
489      switch (node->pn_op) {      switch (node->pn_op) {
490      case JSOP_ADD:      case JSOP_ADD:
# Line 494  Line 505 
505        break;        break;
506      }      }
507      Stream_write_string(f, "= ");      Stream_write_string(f, "= ");
508      instrument_expression(node->pn_right, f);      output_expression(node->pn_right, f, false);
509      break;      break;
510    case TOK_HOOK:    case TOK_HOOK:
511      instrument_expression(node->pn_kid1, f);      output_expression(node->pn_kid1, f, parenthesize_object_literals);
512      Stream_write_string(f, "? ");      Stream_write_string(f, "? ");
513      instrument_expression(node->pn_kid2, f);      output_expression(node->pn_kid2, f, false);
514      Stream_write_string(f, ": ");      Stream_write_string(f, ": ");
515      instrument_expression(node->pn_kid3, f);      output_expression(node->pn_kid3, f, false);
516      break;      break;
517    case TOK_OR:    case TOK_OR:
518    case TOK_AND:    case TOK_AND:
# Line 517  Line 528 
528    case TOK_DIVOP:    case TOK_DIVOP:
529      switch (node->pn_arity) {      switch (node->pn_arity) {
530      case PN_BINARY:      case PN_BINARY:
531        instrument_expression(node->pn_left, f);        output_expression(node->pn_left, f, parenthesize_object_literals);
532        Stream_printf(f, " %s ", get_op(node->pn_op));        Stream_printf(f, " %s ", get_op(node->pn_op));
533        instrument_expression(node->pn_right, f);        output_expression(node->pn_right, f, false);
534        break;        break;
535      case PN_LIST:      case PN_LIST:
536        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) {
537          if (p != node->pn_head) {          if (p == node->pn_head) {
538              output_expression(p, f, parenthesize_object_literals);
539            }
540            else {
541            Stream_printf(f, " %s ", get_op(node->pn_op));            Stream_printf(f, " %s ", get_op(node->pn_op));
542              output_expression(p, f, false);
543          }          }
         instrument_expression(p, f);  
544        }        }
545        break;        break;
546      default:      default:
# Line 537  Line 551 
551      switch (node->pn_op) {      switch (node->pn_op) {
552      case JSOP_NEG:      case JSOP_NEG:
553        Stream_write_char(f, '-');        Stream_write_char(f, '-');
554        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, false);
555        break;        break;
556      case JSOP_POS:      case JSOP_POS:
557        Stream_write_char(f, '+');        Stream_write_char(f, '+');
558        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, false);
559        break;        break;
560      case JSOP_NOT:      case JSOP_NOT:
561        Stream_write_char(f, '!');        Stream_write_char(f, '!');
562        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, false);
563        break;        break;
564      case JSOP_BITNOT:      case JSOP_BITNOT:
565        Stream_write_char(f, '~');        Stream_write_char(f, '~');
566        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, false);
567        break;        break;
568      case JSOP_TYPEOF:      case JSOP_TYPEOF:
569        Stream_write_string(f, "typeof ");        Stream_write_string(f, "typeof ");
570        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, false);
571        break;        break;
572      case JSOP_VOID:      case JSOP_VOID:
573        Stream_write_string(f, "void ");        Stream_write_string(f, "void ");
574        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, false);
575        break;        break;
576      default:      default:
577        fatal("%s: unknown operator (%d) in file", file_id, node->pn_op);        fatal_source(file_id, node->pn_pos.begin.lineno, "unknown operator (%d)", node->pn_op);
578        break;        break;
579      }      }
580      break;      break;
# Line 574  Line 588 
588      case JSOP_INCPROP:      case JSOP_INCPROP:
589      case JSOP_INCELEM:      case JSOP_INCELEM:
590        Stream_write_string(f, "++");        Stream_write_string(f, "++");
591        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, false);
592        break;        break;
593      case JSOP_DECNAME:      case JSOP_DECNAME:
594      case JSOP_DECPROP:      case JSOP_DECPROP:
595      case JSOP_DECELEM:      case JSOP_DECELEM:
596        Stream_write_string(f, "--");        Stream_write_string(f, "--");
597        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, false);
598        break;        break;
599      case JSOP_NAMEINC:      case JSOP_NAMEINC:
600      case JSOP_PROPINC:      case JSOP_PROPINC:
601      case JSOP_ELEMINC:      case JSOP_ELEMINC:
602        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, parenthesize_object_literals);
603        Stream_write_string(f, "++");        Stream_write_string(f, "++");
604        break;        break;
605      case JSOP_NAMEDEC:      case JSOP_NAMEDEC:
606      case JSOP_PROPDEC:      case JSOP_PROPDEC:
607      case JSOP_ELEMDEC:      case JSOP_ELEMDEC:
608        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, parenthesize_object_literals);
609        Stream_write_string(f, "--");        Stream_write_string(f, "--");
610        break;        break;
611      default:      default:
# Line 605  Line 619 
619      break;      break;
620    case TOK_DELETE:    case TOK_DELETE:
621      Stream_write_string(f, "delete ");      Stream_write_string(f, "delete ");
622      instrument_expression(node->pn_kid, f);      output_expression(node->pn_kid, f, false);
623      break;      break;
624    case TOK_DOT:    case TOK_DOT:
625        /* numeric literals must be parenthesized */
626        switch (node->pn_expr->pn_type) {
627        case TOK_NUMBER:
628          Stream_write_char(f, '(');
629          output_expression(node->pn_expr, f, false);
630          Stream_write_char(f, ')');
631          break;
632        default:
633          output_expression(node->pn_expr, f, true);
634          break;
635        }
636      /*      /*
637      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'
638      contains illegal characters, we have to use the subscript syntax instead of      contains illegal characters, we have to use the subscript syntax instead of
639      the dot syntax.      the dot syntax.
640      */      */
     instrument_expression(node->pn_expr, f);  
641      assert(ATOM_IS_STRING(node->pn_atom));      assert(ATOM_IS_STRING(node->pn_atom));
642      {      {
643        JSString * s = ATOM_TO_STRING(node->pn_atom);        JSString * s = ATOM_TO_STRING(node->pn_atom);
# Line 642  Line 666 
666      }      }
667      break;      break;
668    case TOK_LB:    case TOK_LB:
669      instrument_expression(node->pn_left, f);      output_expression(node->pn_left, f, false);
670      Stream_write_char(f, '[');      Stream_write_char(f, '[');
671      instrument_expression(node->pn_right, f);      output_expression(node->pn_right, f, false);
672      Stream_write_char(f, ']');      Stream_write_char(f, ']');
673      break;      break;
674    case TOK_LP:    case TOK_LP:
# Line 658  Line 682 
682        }        }
683        /* TOK_COMMA is a special case: a hole in the array */        /* TOK_COMMA is a special case: a hole in the array */
684        if (p->pn_type != TOK_COMMA) {        if (p->pn_type != TOK_COMMA) {
685          instrument_expression(p, f);          output_expression(p, f, false);
686        }        }
687      }      }
688      if (node->pn_extra == PNX_ENDCOMMA) {      if (node->pn_extra == PNX_ENDCOMMA) {
# Line 667  Line 691 
691      Stream_write_char(f, ']');      Stream_write_char(f, ']');
692      break;      break;
693    case TOK_RC:    case TOK_RC:
694        if (parenthesize_object_literals) {
695          Stream_write_char(f, '(');
696        }
697      Stream_write_char(f, '{');      Stream_write_char(f, '{');
698      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) {
699        if (p->pn_type != TOK_COLON) {        if (p->pn_type != TOK_COLON) {
700          fatal("unsupported node type in file %s: %d", file_id, p->pn_type);          fatal_source(file_id, p->pn_pos.begin.lineno, "unsupported node type (%d)", p->pn_type);
701        }        }
702        if (p != node->pn_head) {        if (p != node->pn_head) {
703          Stream_write_string(f, ", ");          Stream_write_string(f, ", ");
# Line 686  Line 713 
713          else {          else {
714            Stream_write_string(f, "set ");            Stream_write_string(f, "set ");
715          }          }
716          instrument_expression(p->pn_left, f);          output_expression(p->pn_left, f, false);
717          if (p->pn_right->pn_type != TOK_FUNCTION) {          if (p->pn_right->pn_type != TOK_FUNCTION) {
718            fatal("parse error: expected function");            fatal_source(file_id, p->pn_pos.begin.lineno, "expected function");
719          }          }
720          instrument_function(p->pn_right, f, 0, FUNCTION_GETTER_OR_SETTER);          instrument_function(p->pn_right, f, 0, FUNCTION_GETTER_OR_SETTER);
721          break;          break;
722        default:        default:
723          instrument_expression(p->pn_left, f);          output_expression(p->pn_left, f, false);
724          Stream_write_string(f, ": ");          Stream_write_string(f, ": ");
725          instrument_expression(p->pn_right, f);          output_expression(p->pn_right, f, false);
726          break;          break;
727        }        }
728      }      }
729      Stream_write_char(f, '}');      Stream_write_char(f, '}');
730        if (parenthesize_object_literals) {
731          Stream_write_char(f, ')');
732        }
733      break;      break;
734    case TOK_RP:    case TOK_RP:
735      Stream_write_char(f, '(');      Stream_write_char(f, '(');
736      instrument_expression(node->pn_kid, f);      output_expression(node->pn_kid, f, false);
737      Stream_write_char(f, ')');      Stream_write_char(f, ')');
738      break;      break;
739    case TOK_NAME:    case TOK_NAME:
740      print_string_atom(node->pn_atom, f);      print_string_atom(node->pn_atom, f);
741        if (node->pn_expr != NULL) {
742          Stream_write_string(f, " = ");
743          output_expression(node->pn_expr, f, false);
744        }
745      break;      break;
746    case TOK_STRING:    case TOK_STRING:
747      print_quoted_string_atom(node->pn_atom, f);      print_quoted_string_atom(node->pn_atom, f);
# Line 755  Line 789 
789      }      }
790      break;      break;
791    case TOK_INSTANCEOF:    case TOK_INSTANCEOF:
792      instrument_expression(node->pn_left, f);      output_expression(node->pn_left, f, parenthesize_object_literals);
793      Stream_write_string(f, " instanceof ");      Stream_write_string(f, " instanceof ");
794      instrument_expression(node->pn_right, f);      output_expression(node->pn_right, f, false);
795      break;      break;
796    case TOK_IN:    case TOK_IN:
797      instrument_expression(node->pn_left, f);      output_expression(node->pn_left, f, false);
798      Stream_write_string(f, " in ");      Stream_write_string(f, " in ");
799      instrument_expression(node->pn_right, f);      output_expression(node->pn_right, f, false);
800      break;      break;
801    case TOK_LEXICALSCOPE:    case TOK_LEXICALSCOPE:
802      assert(node->pn_arity == PN_NAME);      assert(node->pn_arity == PN_NAME);
# Line 773  Line 807 
807      assert(node->pn_expr->pn_left->pn_arity == PN_LIST);      assert(node->pn_expr->pn_left->pn_arity == PN_LIST);
808      instrument_declarations(node->pn_expr->pn_left, f);      instrument_declarations(node->pn_expr->pn_left, f);
809      Stream_write_string(f, ") ");      Stream_write_string(f, ") ");
810      instrument_expression(node->pn_expr->pn_right, f);      output_expression(node->pn_expr->pn_right, f, true);
811      break;      break;
812    case TOK_YIELD:    case TOK_YIELD:
813      assert(node->pn_arity == PN_UNARY);      assert(node->pn_arity == PN_UNARY);
814      Stream_write_string(f, "yield");      Stream_write_string(f, "yield");
815      if (node->pn_kid != NULL) {      if (node->pn_kid != NULL) {
816        Stream_write_char(f, ' ');        Stream_write_char(f, ' ');
817        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, true);
818      }      }
819      break;      break;
820    case TOK_ARRAYCOMP:    case TOK_ARRAYCOMP:
# Line 814  Line 848 
848      instrument_declarations(node, f);      instrument_declarations(node, f);
849      break;      break;
850    default:    default:
851      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);
852    }    }
853  }  }
854    
# Line 822  Line 856 
856    switch (node->pn_type) {    switch (node->pn_type) {
857    case TOK_FUNCTION:    case TOK_FUNCTION:
858      instrument_function(node, f, indent, FUNCTION_NORMAL);      instrument_function(node, f, indent, FUNCTION_NORMAL);
859        Stream_write_char(f, '\n');
860      break;      break;
861    case TOK_LC:    case TOK_LC:
862      assert(node->pn_arity == PN_LIST);      assert(node->pn_arity == PN_LIST);
# Line 843  Line 878 
878      uint16_t line = node->pn_pos.begin.lineno;      uint16_t line = node->pn_pos.begin.lineno;
879      if (! is_jscoverage_if) {      if (! is_jscoverage_if) {
880        if (line > num_lines) {        if (line > num_lines) {
881          fatal("%s: script contains more than 65,535 lines", file_id);          fatal("file %s contains more than 65,535 lines", file_id);
882        }        }
883        if (line >= 2 && exclusive_directives[line - 2]) {        if (line >= 2 && exclusive_directives[line - 2]) {
884          is_jscoverage_if = true;          is_jscoverage_if = true;
# Line 852  Line 887 
887    
888      Stream_printf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
889      Stream_write_string(f, "if (");      Stream_write_string(f, "if (");
890      instrument_expression(node->pn_kid1, f);      output_expression(node->pn_kid1, f, false);
891      Stream_write_string(f, ") {\n");      Stream_write_string(f, ") {\n");
892      if (is_jscoverage_if && node->pn_kid3) {      if (is_jscoverage_if && node->pn_kid3) {
893        uint16_t else_start = node->pn_kid3->pn_pos.begin.lineno;        uint16_t else_start = node->pn_kid3->pn_pos.begin.lineno;
# Line 889  Line 924 
924      assert(node->pn_arity == PN_BINARY);      assert(node->pn_arity == PN_BINARY);
925      Stream_printf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
926      Stream_write_string(f, "switch (");      Stream_write_string(f, "switch (");
927      instrument_expression(node->pn_left, f);      output_expression(node->pn_left, f, false);
928      Stream_write_string(f, ") {\n");      Stream_write_string(f, ") {\n");
929      {      {
930        JSParseNode * list = node->pn_right;        JSParseNode * list = node->pn_right;
# Line 901  Line 936 
936          switch (p->pn_type) {          switch (p->pn_type) {
937          case TOK_CASE:          case TOK_CASE:
938            Stream_write_string(f, "case ");            Stream_write_string(f, "case ");
939            instrument_expression(p->pn_left, f);            output_expression(p->pn_left, f, false);
940            Stream_write_string(f, ":\n");            Stream_write_string(f, ":\n");
941            break;            break;
942          case TOK_DEFAULT:          case TOK_DEFAULT:
# Line 925  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, "while (");      Stream_write_string(f, "while (");
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      instrument_statement(node->pn_right, f, indent + 2, false);      instrument_statement(node->pn_right, f, indent + 2, false);
966      Stream_write_string(f, "}\n");      Stream_write_string(f, "}\n");
# Line 938  Line 973 
973      Stream_write_string(f, "}\n");      Stream_write_string(f, "}\n");
974      Stream_printf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
975      Stream_write_string(f, "while (");      Stream_write_string(f, "while (");
976      instrument_expression(node->pn_right, f);      output_expression(node->pn_right, f, false);
977      Stream_write_string(f, ");\n");      Stream_write_string(f, ");\n");
978      break;      break;
979    case TOK_FOR:    case TOK_FOR:
# Line 955  Line 990 
990        assert(node->pn_left->pn_arity == PN_TERNARY);        assert(node->pn_left->pn_arity == PN_TERNARY);
991        Stream_write_string(f, "for (");        Stream_write_string(f, "for (");
992        if (node->pn_left->pn_kid1) {        if (node->pn_left->pn_kid1) {
993          instrument_expression(node->pn_left->pn_kid1, f);          output_expression(node->pn_left->pn_kid1, f, false);
994        }        }
995        Stream_write_string(f, ";");        Stream_write_string(f, ";");
996        if (node->pn_left->pn_kid2) {        if (node->pn_left->pn_kid2) {
997          Stream_write_char(f, ' ');          Stream_write_char(f, ' ');
998          instrument_expression(node->pn_left->pn_kid2, f);          output_expression(node->pn_left->pn_kid2, f, false);
999        }        }
1000        Stream_write_string(f, ";");        Stream_write_string(f, ";");
1001        if (node->pn_left->pn_kid3) {        if (node->pn_left->pn_kid3) {
1002          Stream_write_char(f, ' ');          Stream_write_char(f, ' ');
1003          instrument_expression(node->pn_left->pn_kid3, f);          output_expression(node->pn_left->pn_kid3, f, false);
1004        }        }
1005        Stream_write_char(f, ')');        Stream_write_char(f, ')');
1006        break;        break;
# Line 981  Line 1016 
1016      assert(node->pn_arity == PN_UNARY);      assert(node->pn_arity == PN_UNARY);
1017      Stream_printf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
1018      Stream_write_string(f, "throw ");      Stream_write_string(f, "throw ");
1019      instrument_expression(node->pn_u.unary.kid, f);      output_expression(node->pn_u.unary.kid, f, false);
1020      Stream_write_string(f, ";\n");      Stream_write_string(f, ";\n");
1021      break;      break;
1022    case TOK_TRY:    case TOK_TRY:
# Line 998  Line 1033 
1033          assert(catch->pn_type == TOK_CATCH);          assert(catch->pn_type == TOK_CATCH);
1034          Stream_printf(f, "%*s", indent, "");          Stream_printf(f, "%*s", indent, "");
1035          Stream_write_string(f, "catch (");          Stream_write_string(f, "catch (");
1036          /* this may not be a name - destructuring assignment */          output_expression(catch->pn_kid1, f, false);
         /*  
         assert(catch->pn_kid1->pn_arity == PN_NAME);  
         print_string_atom(catch->pn_kid1->pn_atom, f);  
         */  
         instrument_expression(catch->pn_kid1, f);  
1037          if (catch->pn_kid2) {          if (catch->pn_kid2) {
1038            Stream_write_string(f, " if ");            Stream_write_string(f, " if ");
1039            instrument_expression(catch->pn_kid2, f);            output_expression(catch->pn_kid2, f, false);
1040          }          }
1041          Stream_write_string(f, ") {\n");          Stream_write_string(f, ") {\n");
1042          instrument_statement(catch->pn_kid3, f, indent + 2, false);          instrument_statement(catch->pn_kid3, f, indent + 2, false);
# Line 1041  Line 1071 
1071      assert(node->pn_arity == PN_BINARY);      assert(node->pn_arity == PN_BINARY);
1072      Stream_printf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
1073      Stream_write_string(f, "with (");      Stream_write_string(f, "with (");
1074      instrument_expression(node->pn_left, f);      output_expression(node->pn_left, f, false);
1075      Stream_write_string(f, ") {\n");      Stream_write_string(f, ") {\n");
1076      instrument_statement(node->pn_right, f, indent + 2, false);      instrument_statement(node->pn_right, f, indent + 2, false);
1077      Stream_printf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
# Line 1049  Line 1079 
1079      break;      break;
1080    case TOK_VAR:    case TOK_VAR:
1081      Stream_printf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
1082      instrument_expression(node, f);      output_expression(node, f, false);
1083      Stream_write_string(f, ";\n");      Stream_write_string(f, ";\n");
1084      break;      break;
1085    case TOK_RETURN:    case TOK_RETURN:
# Line 1058  Line 1088 
1088      Stream_write_string(f, "return");      Stream_write_string(f, "return");
1089      if (node->pn_kid != NULL) {      if (node->pn_kid != NULL) {
1090        Stream_write_char(f, ' ');        Stream_write_char(f, ' ');
1091        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, true);
1092      }      }
1093      Stream_write_string(f, ";\n");      Stream_write_string(f, ";\n");
1094      break;      break;
# Line 1066  Line 1096 
1096      assert(node->pn_arity == PN_UNARY);      assert(node->pn_arity == PN_UNARY);
1097      Stream_printf(f, "%*s", indent, "");      Stream_printf(f, "%*s", indent, "");
1098      if (node->pn_kid != NULL) {      if (node->pn_kid != NULL) {
1099        instrument_expression(node->pn_kid, f);        output_expression(node->pn_kid, f, true);
1100      }      }
1101      Stream_write_string(f, ";\n");      Stream_write_string(f, ";\n");
1102      break;      break;
1103    case TOK_COLON:    case TOK_COLON:
1104      {
1105      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 ...  
     */  
1106      Stream_printf(f, "%*s", indent < 2? 0: indent - 2, "");      Stream_printf(f, "%*s", indent < 2? 0: indent - 2, "");
1107      print_string_atom(node->pn_atom, f);      print_string_atom(node->pn_atom, f);
1108      Stream_write_string(f, ":\n");      Stream_write_string(f, ":\n");
1109      /*      JSParseNode * labelled = node->pn_expr;
1110      ... use output_statement instead of instrument_statement.      if (labelled->pn_type == TOK_LEXICALSCOPE) {
1111      */        labelled = labelled->pn_expr;
1112      output_statement(node->pn_expr, f, indent, false);      }
1113        if (labelled->pn_type == TOK_LC) {
1114          /* labelled block */
1115          Stream_printf(f, "%*s", indent, "");
1116          Stream_write_string(f, "{\n");
1117          instrument_statement(labelled, f, indent + 2, false);
1118          Stream_printf(f, "%*s", indent, "");
1119          Stream_write_string(f, "}\n");
1120        }
1121        else {
1122          /*
1123          This one is tricky: can't output instrumentation between the label and the
1124          statement it's supposed to label, so use output_statement instead of
1125          instrument_statement.
1126          */
1127          output_statement(labelled, f, indent, false);
1128        }
1129      break;      break;
1130      }
1131    case TOK_LEXICALSCOPE:    case TOK_LEXICALSCOPE:
1132      /* let statement */      /* let statement */
1133      assert(node->pn_arity == PN_NAME);      assert(node->pn_arity == PN_NAME);
# Line 1126  Line 1170 
1170      case PN_LIST:      case PN_LIST:
1171        /* let definition */        /* let definition */
1172        Stream_printf(f, "%*s", indent, "");        Stream_printf(f, "%*s", indent, "");
1173        instrument_expression(node, f);        output_expression(node, f, false);
1174        Stream_write_string(f, ";\n");        Stream_write_string(f, ";\n");
1175        break;        break;
1176      default:      default:
# Line 1139  Line 1183 
1183      Stream_write_string(f, "debugger;\n");      Stream_write_string(f, "debugger;\n");
1184      break;      break;
1185    default:    default:
1186      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);
1187    }    }
1188  }  }
1189    
# Line 1152  Line 1196 
1196    if (node->pn_type != TOK_LC && node->pn_type != TOK_LEXICALSCOPE) {    if (node->pn_type != TOK_LC && node->pn_type != TOK_LEXICALSCOPE) {
1197      uint16_t line = node->pn_pos.begin.lineno;      uint16_t line = node->pn_pos.begin.lineno;
1198      if (line > num_lines) {      if (line > num_lines) {
1199        fatal("%s: script contains more than 65,535 lines", file_id);        fatal("file %s contains more than 65,535 lines", file_id);
1200      }      }
1201    
1202      /* the root node has line number 0 */      /* the root node has line number 0 */
# Line 1200  Line 1244 
1244  }  }
1245    
1246  static void error_reporter(JSContext * context, const char * message, JSErrorReport * report) {  static void error_reporter(JSContext * context, const char * message, JSErrorReport * report) {
1247    fprintf(stderr, "jscoverage: parse error: line %u: %s\n", report->lineno, message);    warn_source(file_id, report->lineno, "%s", message);
1248  }  }
1249    
1250  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 1209  Line 1253 
1253    /* parse the javascript */    /* parse the javascript */
1254    JSParseContext parse_context;    JSParseContext parse_context;
1255    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)) {
1256      fatal("cannot create token stream from file: %s", file_id);      fatal("cannot create token stream from file %s", file_id);
1257    }    }
1258    JSErrorReporter old_error_reporter = JS_SetErrorReporter(context, error_reporter);    JSErrorReporter old_error_reporter = JS_SetErrorReporter(context, error_reporter);
1259    JSParseNode * node = js_ParseScript(context, global, &parse_context);    JSParseNode * node = js_ParseScript(context, global, &parse_context);
1260    if (node == NULL) {    if (node == NULL) {
1261      js_ReportUncaughtException(context);      js_ReportUncaughtException(context);
1262      fatal("parse error in file: %s", file_id);      fatal("parse error in file %s", file_id);
1263    }    }
1264    JS_SetErrorReporter(context, old_error_reporter);    JS_SetErrorReporter(context, old_error_reporter);
1265    num_lines = node->pn_pos.end.lineno;    num_lines = node->pn_pos.end.lineno;
# Line 1236  Line 1280 
1280    size_t i = 0;    size_t i = 0;
1281    while (i < num_characters) {    while (i < num_characters) {
1282      if (line_number == UINT16_MAX) {      if (line_number == UINT16_MAX) {
1283        fatal("%s: script has more than 65,535 lines", file_id);        fatal("file %s contains more than 65,535 lines", file_id);
1284      }      }
1285      line_number++;      line_number++;
1286      size_t line_start = i;      size_t line_start = i;

Legend:
Removed from v.369  
changed lines
  Added in v.380

  ViewVC Help
Powered by ViewVC 1.1.24