/[jscoverage]/trunk/highlight.c
ViewVC logotype

Diff of /trunk/highlight.c

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

revision 179 by siliconforks, Sun Sep 21 18:35:21 2008 UTC revision 292 by siliconforks, Sun Oct 12 16:41:36 2008 UTC
# Line 21  Line 21 
21    
22  #include "highlight.h"  #include "highlight.h"
23    
24    #include <assert.h>
25  #include <stdlib.h>  #include <stdlib.h>
26  #include <string.h>  #include <string.h>
27    
# Line 80  Line 81 
81    }    }
82  }  }
83    
84  static enum Class ** classes = NULL;  static const char * g_id;
85  static jschar ** lines = NULL;  static const jschar * g_characters;
86    static size_t g_num_characters;
87  static uint16_t num_characters_in_line(jschar * line) {  static Stream * g_output;
88    uint16_t result = 0;  static size_t character_offset;
89    while (line[result] != '\0') {  static uint16_t line_num;
90      result++;  static uint16_t column_num;
91    static enum Class current_class;
92    
93    static void output_character(jschar c, enum Class class) {
94      if (class != current_class) {
95        /* output the end tag */
96        if (current_class != CLASS_NONE) {
97          Stream_write_string(g_output, "</span>");
98        }
99    
100        current_class = class;
101    
102        /* output the start tag */
103        if (current_class != CLASS_NONE) {
104          Stream_printf(g_output, "<span class=\"%s\">", get_class_name(class));
105        }
106    }    }
   return result;  
 }  
107    
108  static void mark_token_chars(enum Class class, uint16_t start_line, uint16_t start_column, uint16_t end_line, uint16_t end_column) {    switch (c) {
109    for (uint16_t i = start_line; i <= end_line; i++) {    case '&':
110      uint16_t c1 = i == start_line? start_column: 0;      Stream_write_string(g_output, "&amp;");
111      uint16_t c2 = i == end_line? end_column: num_characters_in_line(lines[i - 1]);      break;
112      for (uint16_t j = c1; j < c2; j++) {    case '<':
113        classes[i - 1][j] = class;      Stream_write_string(g_output, "&lt;");
114        break;
115      case '>':
116        Stream_write_string(g_output, "&gt;");
117        break;
118      case '\t':
119      case '\n':
120        Stream_write_char(g_output, c);
121        break;
122      default:
123        if (32 <= c && c <= 126) {
124          Stream_write_char(g_output, c);
125      }      }
126        else {
127          Stream_printf(g_output, "&#%d;", c);
128        }
129        break;
130    }    }
131  }  }
132    
133  static void mark_nontoken_chars(uint16_t start_line, uint16_t start_column, uint16_t end_line, uint16_t end_column) {  static void mark_nontoken_chars(uint16_t end_line, uint16_t end_column) {
134    enum State {    enum State {
135      STATE_NORMAL,      STATE_NORMAL,
136      STATE_LINE_COMMENT,      STATE_LINE_COMMENT,
# Line 109  Line 138 
138    };    };
139    
140    enum State state = STATE_NORMAL;    enum State state = STATE_NORMAL;
141    for (uint16_t i = start_line; i <= end_line; i++) {    while (character_offset < g_num_characters) {
142      uint16_t c1 = i == start_line? start_column: 0;      if (end_line != 0 && line_num > end_line) {
143      uint16_t c2 = i == end_line? end_column: num_characters_in_line(lines[i - 1]);        break;
     for (uint16_t j = c1; j < c2; j++) {  
       jschar c = lines[i - 1][j];  
       switch (state) {  
       case STATE_NORMAL:  
         if (c == '/' && j + 1 < c2 && lines[i - 1][j + 1] == '/') {  
           state = STATE_LINE_COMMENT;  
           classes[i - 1][j] = CLASS_COMMENT;  
         }  
         else if (c == '/' && j + 1 < c2 && lines[i - 1][j + 1] == '*') {  
           state = STATE_MULTILINE_COMMENT;  
           classes[i - 1][j] = CLASS_COMMENT;  
           j++;  
           classes[i - 1][j] = CLASS_COMMENT;  
         }  
         else {  
           classes[i - 1][j] = CLASS_NONE;  
         }  
         break;  
       case STATE_LINE_COMMENT:  
         if (c == '\r' || c == '\n' || c == 0x2028 || c == 0x2029) {  
           state = STATE_NORMAL;  
           classes[i - 1][j] = CLASS_NONE;  
         }  
         else {  
           classes[i - 1][j] = CLASS_COMMENT;  
         }  
         break;  
       case STATE_MULTILINE_COMMENT:  
         classes[i - 1][j] = CLASS_COMMENT;  
         if (c == '*' && j + 1 < c2 && lines[i - 1][j + 1] == '/') {  
           j++;  
           classes[i - 1][j] = CLASS_COMMENT;  
           state = STATE_NORMAL;  
         }  
         break;  
       }  
144      }      }
145      /* end of the line */      else if (line_num == end_line && column_num >= end_column) {
146      if (state == STATE_LINE_COMMENT) {        break;
       state = STATE_NORMAL;  
147      }      }
   }  
 }  
148    
149  void jscoverage_highlight_js(JSContext * context, const char * id, const jschar * characters, size_t num_characters, Stream * output) {      jschar c = g_characters[character_offset];
150    /* count the lines - see GetChar in jsscan.c */      if (c == '\0') {
151    size_t i = 0;        fatal("%s: script contains NULL character", g_id);
152    uint16_t num_lines = 0;      }
153    while (i < num_characters) {  
154      if (num_lines == UINT16_MAX) {      switch (state) {
155        fatal("%s: script has more than 65535 lines", id);      case STATE_NORMAL:
156      }        if (c == '/' && character_offset + 1 < g_num_characters && g_characters[character_offset + 1] == '/') {
157      num_lines++;          state = STATE_LINE_COMMENT;
158      jschar c;        }
159      while (i < num_characters) {        else if (c == '/' && character_offset + 1 < g_num_characters && g_characters[character_offset + 1] == '*') {
160        c = characters[i];          state = STATE_MULTILINE_COMMENT;
161        if (c == '\0') {          output_character('/', CLASS_COMMENT);
162          fatal("%s: script contains NULL character", id);          output_character('*', CLASS_COMMENT);
163            character_offset += 2;
164            if (column_num >= UINT16_MAX - 1) {
165              fatal("%s: script contains line with more than 65,535 characters", g_id);
166            }
167            column_num += 2;
168            continue;
169        }        }
170          break;
171        case STATE_LINE_COMMENT:
172        if (c == '\r' || c == '\n' || c == 0x2028 || c == 0x2029) {        if (c == '\r' || c == '\n' || c == 0x2028 || c == 0x2029) {
173          break;          state = STATE_NORMAL;
174        }        }
175        i++;        break;
176      }      case STATE_MULTILINE_COMMENT:
177      if (i < num_characters) {        if (c == '*' && character_offset + 1 < g_num_characters && g_characters[character_offset + 1] == '/') {
178        i++;          output_character('*', CLASS_COMMENT);
179        if (c == '\r' && i < num_characters && characters[i] == '\n') {          output_character('/', CLASS_COMMENT);
180          i++;          state = STATE_NORMAL;
181            character_offset += 2;
182            if (column_num >= UINT16_MAX - 1) {
183              fatal("%s: script contains line with more than 65,535 characters", g_id);
184            }
185            column_num += 2;
186            continue;
187        }        }
188          break;
189      }      }
   }  
190    
191    lines = xnew(jschar *, num_lines);      character_offset++;
192    classes = xnew(enum Class *, num_lines);      if (c == '\r' || c == '\n' || c == 0x2028 || c == 0x2029) {
193          if (line_num == UINT16_MAX) {
194    uint16_t line_num = 0;          fatal("%s: script contains more than 65,535 lines", g_id);
195    i = 0;        }
196    while (i < num_characters) {        line_num++;
197      size_t line_start = i;        column_num = 0;
198      jschar c;        if (c == '\r' && character_offset < g_num_characters && g_characters[character_offset] == '\n') {
199      while (i < num_characters) {          character_offset++;
       c = characters[i];  
       if (c == '\r' || c == '\n' || c == 0x2028 || c == 0x2029) {  
         break;  
200        }        }
201        i++;        output_character('\n', CLASS_NONE);
202      }      }
203      size_t line_end = i;      else {
204      if (i < num_characters) {        if (column_num == UINT16_MAX) {
205        i++;          fatal("%s: script contains line with more than 65,535 characters", g_id);
206        if (c == '\r' && i < num_characters && characters[i] == '\n') {        }
207          i++;        column_num++;
208          if (state == STATE_NORMAL) {
209            output_character(c, CLASS_NONE);
210          }
211          else {
212            output_character(c, CLASS_COMMENT);
213        }        }
214      }      }
     size_t line_length = line_end - line_start;  
     if (line_length >= UINT16_MAX) {  
       fatal("%s: script has line with 65535 characters or more", id);  
     }  
     jschar * line = xnew(jschar, line_length + 1);  
     memcpy(line, characters + line_start, sizeof(jschar) * line_length);  
     line[line_length] = '\0';  
     lines[line_num] = line;  
     classes[line_num] = xnew(enum Class, line_length);  
     line_num++;  
215    }    }
216    }
217    
218    void jscoverage_highlight_js(JSContext * context, const char * id, const jschar * characters, size_t num_characters, Stream * output) {
219      g_id = id;
220      g_characters = characters;
221      g_num_characters = num_characters;
222      g_output = output;
223    
224      character_offset = 0;
225      line_num = 1;
226      column_num = 0;
227      current_class = CLASS_NONE;
228    
229    /* tokenize the JavaScript */    /* tokenize the JavaScript */
230    JSTokenStream * token_stream = js_NewTokenStream(context, characters, num_characters, NULL, 1, NULL);    JSTokenStream * token_stream = js_NewTokenStream(context, characters, num_characters, NULL, 1, NULL);
# Line 258  Line 266 
266       */       */
267      JS_KEEP_ATOMS(cx->runtime);      JS_KEEP_ATOMS(cx->runtime);
268    
   line_num = 1;  
   uint16_t column_num = 0;  
269    for (;;) {    for (;;) {
270      JSTokenType tt = js_GetToken(context, token_stream);      JSTokenType tt = js_GetToken(context, token_stream);
271    
# Line 268  Line 274 
274      }      }
275    
276      if (tt == TOK_EOF) {      if (tt == TOK_EOF) {
277        /* it seems t.pos is invalid for TOK_EOF??? */        mark_nontoken_chars(0, 0);
       /* mark the remaining chars */  
       if (num_lines == 0) {  
         break;  
       }  
       uint16_t end_line = num_lines;  
       uint16_t end_column = num_characters_in_line(lines[num_lines - 1]);  
       mark_nontoken_chars(line_num, column_num, end_line, end_column);  
278        break;        break;
279      }      }
280    
281      /* mark the chars before the token */      /* mark the chars before the token */
282      JSToken t = CURRENT_TOKEN(token_stream);      JSToken t = CURRENT_TOKEN(token_stream);
283      mark_nontoken_chars(line_num, column_num, t.pos.begin.lineno, t.pos.begin.index);      mark_nontoken_chars(t.pos.begin.lineno, t.pos.begin.index);
284    
285      /* mark the token */      /* mark the token */
286      enum Class class;      enum Class class;
# Line 336  Line 335 
335        break;        break;
336      case TOK_INC:      case TOK_INC:
337      case TOK_DEC:      case TOK_DEC:
338          class = CLASS_SYMBOL;
339          /* token_stream->flags does not change w.r.t. TSF_OPERAND */
340          break;
341      case TOK_DOT:      case TOK_DOT:
342      case TOK_LB:      case TOK_LB:
343        class = CLASS_SYMBOL;        class = CLASS_SYMBOL;
# Line 460  Line 462 
462        abort();        abort();
463        break;        break;
464      }      }
     mark_token_chars(class, t.pos.begin.lineno, t.pos.begin.index, t.pos.end.lineno, t.pos.end.index);  
     if (tt == TOK_STRING) {  
       for (uint16_t i = t.pos.begin.index + 1; i < t.pos.end.index - 1; i++) {  
         jschar c = lines[t.pos.begin.lineno - 1][i];  
         if (c == '\\') {  
           mark_token_chars(CLASS_SPECIALCHAR, t.pos.begin.lineno, i, t.pos.begin.lineno, i + 2);  
           i++;  
         }  
       }  
     }  
   
     line_num = t.pos.end.lineno;  
     column_num = t.pos.end.index;  
   }  
465    
466    /* output the highlighted code */      assert(t.pos.begin.lineno == t.pos.end.lineno);
467    enum Class class = CLASS_NONE;      if (t.pos.begin.index > t.pos.end.index) {
468    for (uint16_t i = 0; i < num_lines; i++) {        fatal("%s: script contains line with more than 65,535 characters", id);
469      uint16_t length = num_characters_in_line(lines[i]);      }
470      for (uint16_t j = 0; j < length; j++) {      for (uint16_t i = t.pos.begin.index; i < t.pos.end.index; i++) {
471        jschar c = lines[i][j];        assert(character_offset < num_characters);
472        if (classes[i][j] != class) {        jschar c = characters[character_offset];
473          if (class != CLASS_NONE) {        if (tt == TOK_STRING && c == '\\') {
474            Stream_write_string(output, "</span>");          output_character(c, CLASS_SPECIALCHAR);
475          }          character_offset++;
476          class = classes[i][j];          i++;
477          if (class != CLASS_NONE) {          assert(character_offset < num_characters);
478            Stream_printf(output, "<span class=\"%s\">", get_class_name(class));          c = characters[character_offset];
479          }          output_character(c, CLASS_SPECIALCHAR);
480        }          character_offset++;
       if (c == '&') {  
         Stream_write_string(output, "&amp;");  
       }  
       else if (c == '<') {  
         Stream_write_string(output, "&lt;");  
       }  
       else if (c == '>') {  
         Stream_write_string(output, "&gt;");  
       }  
       else if (c == '\t' || (32 <= c && c <= 126)) {  
         Stream_write_char(output, c);  
481        }        }
482        else {        else {
483          Stream_printf(output, "&#%d;", c);          output_character(c, class);
484            character_offset++;
485        }        }
486      }      }
487      if (class != CLASS_NONE) {  
488        Stream_write_string(output, "</span>");      line_num = t.pos.end.lineno;
489        class = CLASS_NONE;      column_num = t.pos.end.index;
     }  
     Stream_write_char(output, '\n');  
490    }    }
491    
492    for (uint16_t i = 0; i < num_lines; i++) {    if (current_class != CLASS_NONE) {
493      free(lines[i]);      output_character('\n', CLASS_NONE);
     free(classes[i]);  
494    }    }
   free(lines);  
   free(classes);  
495    
496    /* cleanup */    /* cleanup */
497    JS_UNKEEP_ATOMS(cx->runtime);    JS_UNKEEP_ATOMS(cx->runtime);

Legend:
Removed from v.179  
changed lines
  Added in v.292

  ViewVC Help
Powered by ViewVC 1.1.24