/[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 116 by siliconforks, Sat May 31 21:42:36 2008 UTC revision 214 by siliconforks, Fri Oct 3 02:26:04 2008 UTC
# Line 34  Line 34 
34  #include <jsscope.h>  #include <jsscope.h>
35  #include <jsstr.h>  #include <jsstr.h>
36    
37    #include "encoding.h"
38    #include "global.h"
39    #include "highlight.h"
40  #include "resource-manager.h"  #include "resource-manager.h"
41  #include "util.h"  #include "util.h"
42    
# Line 47  Line 50 
50  */  */
51  static const char * file_id = NULL;  static const char * file_id = NULL;
52  static char * lines = NULL;  static char * lines = NULL;
53    static uint16_t num_lines = 0;
54    
55  void jscoverage_init(void) {  void jscoverage_init(void) {
56    runtime = JS_NewRuntime(8L * 1024L * 1024L);    runtime = JS_NewRuntime(8L * 1024L * 1024L);
# Line 75  Line 79 
79  }  }
80    
81  static void print_string(JSString * s, Stream * f) {  static void print_string(JSString * s, Stream * f) {
82    for (size_t i = 0; i < s->length; i++) {    size_t length = JSSTRING_LENGTH(s);
83      char c = s->chars[i];    jschar * characters = JSSTRING_CHARS(s);
84      Stream_write_char(f, c);    for (size_t i = 0; i < length; i++) {
85        jschar c = characters[i];
86        if (32 <= c && c <= 126) {
87          switch (c) {
88          case '"':
89            Stream_write_string(f, "\\\"");
90            break;
91    /*
92          case '\'':
93            Stream_write_string(f, "\\'");
94            break;
95    */
96          case '\\':
97            Stream_write_string(f, "\\\\");
98            break;
99          default:
100            Stream_write_char(f, c);
101            break;
102          }
103        }
104        else {
105          switch (c) {
106          case 0x8:
107            Stream_write_string(f, "\\b");
108            break;
109          case 0x9:
110            Stream_write_string(f, "\\t");
111            break;
112          case 0xa:
113            Stream_write_string(f, "\\n");
114            break;
115          case 0xb:
116            Stream_write_string(f, "\\v");
117            break;
118          case 0xc:
119            Stream_write_string(f, "\\f");
120            break;
121          case 0xd:
122            Stream_write_string(f, "\\r");
123            break;
124          default:
125            Stream_printf(f, "\\u%04x", c);
126            break;
127          }
128        }
129    }    }
130  }  }
131    
# Line 87  Line 135 
135    print_string(s, f);    print_string(s, f);
136  }  }
137    
138  static void print_string_jsval(jsval value, Stream * f) {  static void print_regex(jsval value, Stream * f) {
139    assert(JSVAL_IS_STRING(value));    assert(JSVAL_IS_STRING(value));
140    JSString * s = JSVAL_TO_STRING(value);    JSString * s = JSVAL_TO_STRING(value);
141    print_string(s, f);    size_t length = JSSTRING_LENGTH(s);
142      jschar * characters = JSSTRING_CHARS(s);
143      for (size_t i = 0; i < length; i++) {
144        jschar c = characters[i];
145        if (32 <= c && c <= 126) {
146          Stream_write_char(f, c);
147        }
148        else {
149          Stream_printf(f, "\\u%04x", c);
150        }
151      }
152  }  }
153    
154  static void print_quoted_string_atom(JSAtom * atom, Stream * f) {  static void print_quoted_string_atom(JSAtom * atom, Stream * f) {
155    assert(ATOM_IS_STRING(atom));    assert(ATOM_IS_STRING(atom));
156    JSString * s = ATOM_TO_STRING(atom);    JSString * s = ATOM_TO_STRING(atom);
157    JSString * quoted = js_QuoteString(context, s, '"');    Stream_write_char(f, '"');
158    print_string(quoted, f);    print_string(s, f);
159      Stream_write_char(f, '"');
160  }  }
161    
162  static const char * get_op(uint8 op) {  static const char * get_op(uint8 op) {
# Line 148  Line 207 
207  static void instrument_expression(JSParseNode * node, Stream * f);  static void instrument_expression(JSParseNode * node, Stream * f);
208  static void instrument_statement(JSParseNode * node, Stream * f, int indent);  static void instrument_statement(JSParseNode * node, Stream * f, int indent);
209    
210  static void instrument_function(JSParseNode * node, Stream * f, int indent) {  enum FunctionType {
211      assert(node->pn_arity == PN_FUNC);    FUNCTION_NORMAL,
212      assert(ATOM_IS_OBJECT(node->pn_funAtom));    FUNCTION_GETTER_OR_SETTER
213      JSObject * object = ATOM_TO_OBJECT(node->pn_funAtom);  };
214      assert(JS_ObjectIsFunction(context, object));  
215      JSFunction * function = (JSFunction *) JS_GetPrivate(context, object);  static void instrument_function(JSParseNode * node, Stream * f, int indent, enum FunctionType type) {
216      assert(function);    assert(node->pn_arity == PN_FUNC);
217      assert(object == function->object);    assert(ATOM_IS_OBJECT(node->pn_funAtom));
218      Stream_printf(f, "%*s", indent, "");    JSObject * object = ATOM_TO_OBJECT(node->pn_funAtom);
219      assert(JS_ObjectIsFunction(context, object));
220      JSFunction * function = (JSFunction *) JS_GetPrivate(context, object);
221      assert(function);
222      assert(object == function->object);
223      Stream_printf(f, "%*s", indent, "");
224      if (type == FUNCTION_NORMAL) {
225      Stream_write_string(f, "function");      Stream_write_string(f, "function");
226      }
227    
228      /* function name */    /* function name */
229      if (function->atom) {    if (function->atom) {
230        Stream_write_char(f, ' ');      Stream_write_char(f, ' ');
231        print_string_atom(function->atom, f);      print_string_atom(function->atom, f);
232      }    }
233    
234      /* function parameters */    /* function parameters */
235      Stream_write_string(f, "(");    Stream_write_string(f, "(");
236      JSAtom ** params = xnew(JSAtom *, function->nargs);    JSAtom ** params = xnew(JSAtom *, function->nargs);
237      for (int i = 0; i < function->nargs; i++) {    for (int i = 0; i < function->nargs; i++) {
238        /* initialize to NULL for sanity check */      /* initialize to NULL for sanity check */
239        params[i] = NULL;      params[i] = NULL;
240      }    }
241      JSScope * scope = OBJ_SCOPE(object);    JSScope * scope = OBJ_SCOPE(object);
242      for (JSScopeProperty * scope_property = SCOPE_LAST_PROP(scope); scope_property != NULL; scope_property = scope_property->parent) {    for (JSScopeProperty * scope_property = SCOPE_LAST_PROP(scope); scope_property != NULL; scope_property = scope_property->parent) {
243        if (scope_property->getter != js_GetArgument) {      if (scope_property->getter != js_GetArgument) {
244          continue;        continue;
245        }      }
246        assert(scope_property->flags & SPROP_HAS_SHORTID);      assert(scope_property->flags & SPROP_HAS_SHORTID);
247        assert((uint16) scope_property->shortid < function->nargs);      assert((uint16) scope_property->shortid < function->nargs);
248        assert(JSID_IS_ATOM(scope_property->id));      assert(JSID_IS_ATOM(scope_property->id));
249        params[(uint16) scope_property->shortid] = JSID_TO_ATOM(scope_property->id);      params[(uint16) scope_property->shortid] = JSID_TO_ATOM(scope_property->id);
250      }
251      for (int i = 0; i < function->nargs; i++) {
252        assert(params[i] != NULL);
253        if (i > 0) {
254          Stream_write_string(f, ", ");
255      }      }
256      for (int i = 0; i < function->nargs; i++) {      if (ATOM_IS_STRING(params[i])) {
257        assert(params[i] != NULL);        print_string_atom(params[i], f);
       if (i > 0) {  
         Stream_write_string(f, ", ");  
       }  
       if (ATOM_IS_STRING(params[i])) {  
         print_string_atom(params[i], f);  
       }  
258      }      }
259      Stream_write_string(f, ") {\n");    }
260      free(params);    Stream_write_string(f, ") {\n");
261      free(params);
262    
263      /* function body */    /* function body */
264      instrument_statement(node->pn_body, f, indent + 2);    instrument_statement(node->pn_body, f, indent + 2);
265    
266      Stream_write_string(f, "}\n");    Stream_write_string(f, "}\n");
267  }  }
268    
269  static void instrument_function_call(JSParseNode * node, Stream * f) {  static void instrument_function_call(JSParseNode * node, Stream * f) {
# Line 228  Line 294 
294  static void instrument_expression(JSParseNode * node, Stream * f) {  static void instrument_expression(JSParseNode * node, Stream * f) {
295    switch (node->pn_type) {    switch (node->pn_type) {
296    case TOK_FUNCTION:    case TOK_FUNCTION:
297      instrument_function(node, f, 0);      instrument_function(node, f, 0, FUNCTION_NORMAL);
298      break;      break;
299    case TOK_COMMA:    case TOK_COMMA:
300      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) {
# Line 435  Line 501 
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->pn_left, f);  
505        Stream_write_string(f, ": ");        /* check whether this is a getter or setter */
506        instrument_expression(p->pn_right, f);        switch (p->pn_op) {
507          case JSOP_GETTER:
508            Stream_write_string(f, "get ");
509            instrument_expression(p->pn_left, f);
510            instrument_function(p->pn_right, f, 0, FUNCTION_GETTER_OR_SETTER);
511            break;
512          case JSOP_SETTER:
513            Stream_write_string(f, "set ");
514            instrument_expression(p->pn_left, f);
515            instrument_function(p->pn_right, f, 0, FUNCTION_GETTER_OR_SETTER);
516            break;
517          default:
518            instrument_expression(p->pn_left, f);
519            Stream_write_string(f, ": ");
520            instrument_expression(p->pn_right, f);
521            break;
522          }
523      }      }
524      Stream_write_char(f, '}');      Stream_write_char(f, '}');
525      break;      break;
# Line 464  Line 546 
546          JSObject * object = ATOM_TO_OBJECT(node->pn_atom);          JSObject * object = ATOM_TO_OBJECT(node->pn_atom);
547          jsval result;          jsval result;
548          js_regexp_toString(context, object, 0, NULL, &result);          js_regexp_toString(context, object, 0, NULL, &result);
549          print_string_jsval(result, f);          print_regex(result, f);
550        }        }
551        break;        break;
552      default:      default:
# Line 541  Line 623 
623  static void output_statement(JSParseNode * node, Stream * f, int indent) {  static void output_statement(JSParseNode * node, Stream * f, int indent) {
624    switch (node->pn_type) {    switch (node->pn_type) {
625    case TOK_FUNCTION:    case TOK_FUNCTION:
626      instrument_function(node, f, indent);      instrument_function(node, f, indent, FUNCTION_NORMAL);
627      break;      break;
628    case TOK_LC:    case TOK_LC:
629      assert(node->pn_arity == PN_LIST);      assert(node->pn_arity == PN_LIST);
# Line 793  Line 875 
875  */  */
876  static void instrument_statement(JSParseNode * node, Stream * f, int indent) {  static void instrument_statement(JSParseNode * node, Stream * f, int indent) {
877    if (node->pn_type != TOK_LC) {    if (node->pn_type != TOK_LC) {
878      int line = node->pn_pos.begin.lineno;      uint16_t line = node->pn_pos.begin.lineno;
879        if (line > num_lines) {
880          fatal("%s: script contains more than 65,535 lines", file_id);
881        }
882    
883      /* the root node has line number 0 */      /* the root node has line number 0 */
884      if (line != 0) {      if (line != 0) {
885        Stream_printf(f, "%*s", indent, "");        Stream_printf(f, "%*s", indent, "");
# Line 804  Line 890 
890    output_statement(node, f, indent);    output_statement(node, f, indent);
891  }  }
892    
893  void jscoverage_instrument_js(const char * id, Stream * input, Stream * output) {  static bool characters_start_with(const jschar * characters, size_t line_start, size_t line_end, const char * prefix) {
894      const jschar * characters_end = characters + line_end;
895      const jschar * cp = characters + line_start;
896      const char * bp = prefix;
897      for (;;) {
898        if (*bp == '\0') {
899          return true;
900        }
901        else if (cp == characters_end) {
902          return false;
903        }
904        else if (*cp != *bp) {
905          return false;
906        }
907        bp++;
908        cp++;
909      }
910    }
911    
912    void jscoverage_instrument_js(const char * id, const uint16_t * characters, size_t num_characters, Stream * output) {
913    file_id = id;    file_id = id;
914    
915    /* scan the javascript */    /* scan the javascript */
916    size_t input_length = input->length;    JSTokenStream * token_stream = js_NewTokenStream(context, characters, num_characters, NULL, 1, NULL);
   jschar * base = js_InflateString(context, (char *) input->data, &input_length);  
   if (base == NULL) {  
     fatal("out of memory");  
   }  
   JSTokenStream * token_stream = js_NewTokenStream(context, base, input_length, NULL, 1, NULL);  
917    if (token_stream == NULL) {    if (token_stream == NULL) {
918      fatal("cannot create token stream from file: %s", file_id);      fatal("cannot create token stream from file: %s", file_id);
919    }    }
# Line 823  Line 923 
923    if (node == NULL) {    if (node == NULL) {
924      fatal("parse error in file: %s", file_id);      fatal("parse error in file: %s", file_id);
925    }    }
926    int num_lines = node->pn_pos.end.lineno;    num_lines = node->pn_pos.end.lineno;
927    lines = xmalloc(num_lines);    lines = xmalloc(num_lines);
928    for (int i = 0; i < num_lines; i++) {    for (int i = 0; i < num_lines; i++) {
929      lines[i] = 0;      lines[i] = 0;
# Line 856  Line 956 
956    
957    /* copy the instrumented source code to the output */    /* copy the instrumented source code to the output */
958    Stream_write(output, instrumented->data, instrumented->length);    Stream_write(output, instrumented->data, instrumented->length);
   Stream_write_char(output, '\n');  
959    
960    /* copy the original source to the output */    /* conditionals */
961      bool has_conditionals = false;
962      size_t line_number = 0;
963    size_t i = 0;    size_t i = 0;
964    while (i < input_length) {    while (i < num_characters) {
965      Stream_write_string(output, "// ");      line_number++;
966      size_t line_start = i;      size_t line_start = i;
967      while (i < input_length && base[i] != '\r' && base[i] != '\n') {      jschar c;
968        i++;      bool done = false;
969      }      while (! done && i < num_characters) {
970          c = characters[i];
971      size_t line_end = i;        switch (c) {
972      if (i < input_length) {        case '\r':
973        if (base[i] == '\r') {        case '\n':
974          line_end = i;        case 0x2028:
975          case 0x2029:
976            done = true;
977            break;
978          default:
979          i++;          i++;
980          if (i < input_length && base[i] == '\n') {          break;
           i++;  
         }  
981        }        }
982        else if (base[i] == '\n') {      }
983          line_end = i;      size_t line_end = i;
984        if (i < num_characters) {
985          i++;
986          if (c == '\r' && i < num_characters && characters[i] == '\n') {
987          i++;          i++;
988        }        }
989        else {      }
990          abort();      if (characters_start_with(characters, line_start, line_end, "//#JSCOVERAGE_IF")) {
991          if (! has_conditionals) {
992            has_conditionals = true;
993            Stream_printf(output, "_$jscoverage['%s'].conditionals = [];\n", file_id);
994          }
995          Stream_write_string(output, "if (!(");
996          for (size_t j = line_start + 16; j < line_end; j++) {
997            jschar c = characters[j];
998            if (c == '\t' || (32 <= c && c <= 126)) {
999              Stream_write_char(output, c);
1000            }
1001            else {
1002              Stream_printf(output, "\\u%04x", c);
1003            }
1004        }        }
1005          Stream_write_string(output, ")) {\n");
1006          Stream_printf(output, "  _$jscoverage['%s'].conditionals[%d] = ", file_id, line_number);
1007        }
1008        else if (characters_start_with(characters, line_start, line_end, "//#JSCOVERAGE_ENDIF")) {
1009          Stream_printf(output, "%d;\n", line_number);
1010          Stream_printf(output, "}\n");
1011      }      }
   
     char * line = js_DeflateString(context, base + line_start, line_end - line_start);  
     Stream_write_string(output, line);  
     Stream_write_char(output, '\n');  
     JS_free(context, line);  
1012    }    }
1013    
1014    Stream_delete(instrumented);    /* copy the original source to the output */
1015      Stream_printf(output, "_$jscoverage['%s'].source = ", file_id);
1016      jscoverage_write_source(id, characters, num_characters, output);
1017      Stream_printf(output, ";\n");
1018    
1019    JS_free(context, base);    Stream_delete(instrumented);
1020    
1021    file_id = NULL;    file_id = NULL;
1022  }  }
1023    
1024    void jscoverage_write_source(const char * id, const jschar * characters, size_t num_characters, Stream * output) {
1025      Stream_write_string(output, "[");
1026      if (jscoverage_highlight) {
1027        Stream * highlighted_stream = Stream_new(num_characters);
1028        jscoverage_highlight_js(context, id, characters, num_characters, highlighted_stream);
1029        size_t i = 0;
1030        while (i < highlighted_stream->length) {
1031          if (i > 0) {
1032            Stream_write_char(output, ',');
1033          }
1034    
1035          Stream_write_char(output, '"');
1036          bool done = false;
1037          while (! done) {
1038            char c = highlighted_stream->data[i];
1039            switch (c) {
1040            case 0x8:
1041              /* backspace */
1042              Stream_write_string(output, "\\b");
1043              break;
1044            case 0x9:
1045              /* horizontal tab */
1046              Stream_write_string(output, "\\t");
1047              break;
1048            case 0xa:
1049              /* line feed (new line) */
1050              done = true;
1051              break;
1052            case 0xb:
1053              /* vertical tab */
1054              Stream_write_string(output, "\\v");
1055              break;
1056            case 0xc:
1057              /* form feed */
1058              Stream_write_string(output, "\\f");
1059              break;
1060            case 0xd:
1061              /* carriage return */
1062              done = true;
1063              if (i + 1 < highlighted_stream->length && highlighted_stream->data[i + 1] == '\n') {
1064                i++;
1065              }
1066              break;
1067            case '"':
1068              Stream_write_string(output, "\\\"");
1069              break;
1070            case '\\':
1071              Stream_write_string(output, "\\\\");
1072              break;
1073            default:
1074              Stream_write_char(output, c);
1075              break;
1076            }
1077            i++;
1078            if (i >= highlighted_stream->length) {
1079              done = true;
1080            }
1081          }
1082          Stream_write_char(output, '"');
1083        }
1084        Stream_delete(highlighted_stream);
1085      }
1086      else {
1087        size_t i = 0;
1088        while (i < num_characters) {
1089          if (i > 0) {
1090            Stream_write_char(output, ',');
1091          }
1092    
1093          Stream_write_char(output, '"');
1094          bool done = false;
1095          while (! done) {
1096            jschar c = characters[i];
1097            switch (c) {
1098            case 0x8:
1099              /* backspace */
1100              Stream_write_string(output, "\\b");
1101              break;
1102            case 0x9:
1103              /* horizontal tab */
1104              Stream_write_string(output, "\\t");
1105              break;
1106            case 0xa:
1107              /* line feed (new line) */
1108              done = true;
1109              break;
1110            case 0xb:
1111              /* vertical tab */
1112              Stream_write_string(output, "\\v");
1113              break;
1114            case 0xc:
1115              /* form feed */
1116              Stream_write_string(output, "\\f");
1117              break;
1118            case 0xd:
1119              /* carriage return */
1120              done = true;
1121              if (i + 1 < num_characters && characters[i + 1] == '\n') {
1122                i++;
1123              }
1124              break;
1125            case '"':
1126              Stream_write_string(output, "\\\"");
1127              break;
1128            case '\\':
1129              Stream_write_string(output, "\\\\");
1130              break;
1131            case '&':
1132              Stream_write_string(output, "&amp;");
1133              break;
1134            case '<':
1135              Stream_write_string(output, "&lt;");
1136              break;
1137            case '>':
1138              Stream_write_string(output, "&gt;");
1139              break;
1140            case 0x2028:
1141            case 0x2029:
1142              done = true;
1143              break;
1144            default:
1145              if (32 <= c && c <= 126) {
1146                Stream_write_char(output, c);
1147              }
1148              else {
1149                Stream_printf(output, "&#%d;", c);
1150              }
1151              break;
1152            }
1153            i++;
1154            if (i >= num_characters) {
1155              done = true;
1156            }
1157          }
1158          Stream_write_char(output, '"');
1159        }
1160      }
1161      Stream_write_string(output, "]");
1162    }
1163    
1164  void jscoverage_copy_resources(const char * destination_directory) {  void jscoverage_copy_resources(const char * destination_directory) {
1165    copy_resource("jscoverage.html", destination_directory);    copy_resource("jscoverage.html", destination_directory);
1166    copy_resource("jscoverage.css", destination_directory);    copy_resource("jscoverage.css", destination_directory);
1167    copy_resource("jscoverage.js", destination_directory);    copy_resource("jscoverage.js", destination_directory);
1168      copy_resource("jscoverage-ie.css", destination_directory);
1169    copy_resource("jscoverage-throbber.gif", destination_directory);    copy_resource("jscoverage-throbber.gif", destination_directory);
1170    copy_resource("jscoverage-sh_main.js", destination_directory);    copy_resource("jscoverage-highlight.css", destination_directory);
   copy_resource("jscoverage-sh_javascript.js", destination_directory);  
   copy_resource("jscoverage-sh_nedit.css", destination_directory);  
1171  }  }
1172    
1173  /*  /*
# Line 940  Line 1202 
1202    JS_HashTableDestroy(coverage->coverage_table);    JS_HashTableDestroy(coverage->coverage_table);
1203    struct FileCoverageList * p = coverage->coverage_list;    struct FileCoverageList * p = coverage->coverage_list;
1204    while (p != NULL) {    while (p != NULL) {
1205      free(p->file_coverage->lines);      free(p->file_coverage->coverage_lines);
1206      free(p->file_coverage->source);      if (p->file_coverage->source_lines != NULL) {
1207          for (uint32 i = 0; i < p->file_coverage->num_source_lines; i++) {
1208            free(p->file_coverage->source_lines[i]);
1209          }
1210          free(p->file_coverage->source_lines);
1211        }
1212      free(p->file_coverage->id);      free(p->file_coverage->id);
1213      free(p->file_coverage);      free(p->file_coverage);
1214      struct FileCoverageList * q = p;      struct FileCoverageList * q = p;
# Line 1063  Line 1330 
1330          }          }
1331          else if (strcmp(s, "source") == 0) {          else if (strcmp(s, "source") == 0) {
1332            source = element->pn_right;            source = element->pn_right;
1333            if (source->pn_type != TOK_STRING || ! ATOM_IS_STRING(source->pn_atom)) {            if (source->pn_type != TOK_RB) {
1334              return -1;              return -1;
1335            }            }
1336          }          }
# Line 1087  Line 1354 
1354        char * id = xstrdup(id_bytes);        char * id = xstrdup(id_bytes);
1355        file_coverage = xmalloc(sizeof(FileCoverage));        file_coverage = xmalloc(sizeof(FileCoverage));
1356        file_coverage->id = id;        file_coverage->id = id;
1357        file_coverage->num_lines = array->pn_count - 1;        file_coverage->num_coverage_lines = array->pn_count;
1358        file_coverage->lines = xnew(int, array->pn_count);        file_coverage->coverage_lines = xnew(int, array->pn_count);
1359        if (source == NULL) {        if (source == NULL) {
1360          file_coverage->source = NULL;          file_coverage->source_lines = NULL;
1361        }        }
1362        else {        else {
1363          file_coverage->source = xstrdup(JS_GetStringBytes(ATOM_TO_STRING(source->pn_atom)));          file_coverage->num_source_lines = source->pn_count;
1364            file_coverage->source_lines = xnew(char *, source->pn_count);
1365            uint32 i = 0;
1366            for (JSParseNode * element = source->pn_head; element != NULL; element = element->pn_next, i++) {
1367              if (element->pn_type != TOK_STRING) {
1368                return -1;
1369              }
1370              file_coverage->source_lines[i] = xstrdup(JS_GetStringBytes(ATOM_TO_STRING(element->pn_atom)));
1371            }
1372            assert(i == source->pn_count);
1373        }        }
1374    
1375        /* set coverage for all lines */        /* set coverage for all lines */
1376        uint32 i = 0;        uint32 i = 0;
1377        for (JSParseNode * element = array->pn_head; element != NULL; element = element->pn_next, i++) {        for (JSParseNode * element = array->pn_head; element != NULL; element = element->pn_next, i++) {
1378          if (element->pn_type == TOK_NUMBER) {          if (element->pn_type == TOK_NUMBER) {
1379            file_coverage->lines[i] = (int) element->pn_dval;            file_coverage->coverage_lines[i] = (int) element->pn_dval;
1380          }          }
1381          else if (element->pn_type == TOK_PRIMARY && element->pn_op == JSOP_NULL) {          else if (element->pn_type == TOK_PRIMARY && element->pn_op == JSOP_NULL) {
1382            file_coverage->lines[i] = -1;            file_coverage->coverage_lines[i] = -1;
1383          }          }
1384          else {          else {
1385            return -1;            return -1;
# Line 1121  Line 1397 
1397      else {      else {
1398        /* sanity check */        /* sanity check */
1399        assert(strcmp(file_coverage->id, id_bytes) == 0);        assert(strcmp(file_coverage->id, id_bytes) == 0);
1400        if (file_coverage->num_lines != array->pn_count - 1) {        if (file_coverage->num_coverage_lines != array->pn_count) {
1401          return -2;          return -2;
1402        }        }
1403    
# Line 1129  Line 1405 
1405        uint32 i = 0;        uint32 i = 0;
1406        for (JSParseNode * element = array->pn_head; element != NULL; element = element->pn_next, i++) {        for (JSParseNode * element = array->pn_head; element != NULL; element = element->pn_next, i++) {
1407          if (element->pn_type == TOK_NUMBER) {          if (element->pn_type == TOK_NUMBER) {
1408            if (file_coverage->lines[i] == -1) {            if (file_coverage->coverage_lines[i] == -1) {
1409              return -2;              return -2;
1410            }            }
1411            file_coverage->lines[i] += (int) element->pn_dval;            file_coverage->coverage_lines[i] += (int) element->pn_dval;
1412          }          }
1413          else if (element->pn_type == TOK_PRIMARY && element->pn_op == JSOP_NULL) {          else if (element->pn_type == TOK_PRIMARY && element->pn_op == JSOP_NULL) {
1414            if (file_coverage->lines[i] != -1) {            if (file_coverage->coverage_lines[i] != -1) {
1415              return -2;              return -2;
1416            }            }
1417          }          }
# Line 1146  Line 1422 
1422        assert(i == array->pn_count);        assert(i == array->pn_count);
1423    
1424        /* if this JSON file has source, use it */        /* if this JSON file has source, use it */
1425        if (file_coverage->source == NULL && source != NULL) {        if (file_coverage->source_lines == NULL && source != NULL) {
1426          file_coverage->source = xstrdup(JS_GetStringBytes(ATOM_TO_STRING(source->pn_atom)));          file_coverage->num_source_lines = source->pn_count;
1427            file_coverage->source_lines = xnew(char *, source->pn_count);
1428            uint32 i = 0;
1429            for (JSParseNode * element = source->pn_head; element != NULL; element = element->pn_next, i++) {
1430              if (element->pn_type != TOK_STRING) {
1431                return -1;
1432              }
1433              file_coverage->source_lines[i] = xstrdup(JS_GetStringBytes(ATOM_TO_STRING(element->pn_atom)));
1434            }
1435            assert(i == source->pn_count);
1436        }        }
1437      }      }
1438    }    }

Legend:
Removed from v.116  
changed lines
  Added in v.214

  ViewVC Help
Powered by ViewVC 1.1.24