/************************************************************
 *
 *  JavaScript の構文色分け表示
 *
 *    ソースがＣ言語風なのは仕方ないなぁ
 *
 *  Copyright (c) 2005, 2006, 2009 AOK. All Rights Reserved.
 *
 ************************************************************/

function JSParser() {
//////////////////////////////////////////////////////////
this.color_keyword = "<span style='color:blue'>";
this.color_comment = "<span style='color:#C00000'>";
this.color_string  = "<span style='color:teal'>";
this.color_end     = "</span>";

var __keys = new Array(
  "abstract","assert","boolean","break","byte","case","catch","char","class",
  "const","continue","debugger","decimal","default","delete","do","double","else",
  "ensure","enum","event","export","extends","false","final","finally","float",
  "for","function","get","goto","if","implements","import","in","instanceof","int",
  "interface","internal","invariant","long","namespace","native","new","null",
  "package","private","protected","protected","public","require","return","sbyte",
  "set","short","static","super","switch","synchronized","this","throw","throws",
  "transient","true","try","typeof","uint","ulong","use","ushort","var","void",
  "volatile","while","with"
);

var src, dest, chbuf;
var pos, error;
var cl_key, cl_com, cl_str, cl_end;

/* １文字取ってくる */
var getnext = function() {
  if (pos >= src.length) {
    error++;
    return false;
  }
  chbuf = src.charAt(pos++);
  return true;
};

/* １文字戻す */
var ungetnext = function() {
  if (--pos < 0) error++;
};

/* 予約語の連想配列を作成 */
var keys = new Object();
(function() {
  for (var i = 0; i < __keys.length; i++)
    keys['_' + __keys[i]] = true;
})();

/* 標準の書き出し */
var normal = function() {
  if (chbuf == ">") dest += "&gt;";
  else if (chbuf == "<") dest += "&lt;"; 
  else if (chbuf == "&") dest += "&amp;";
  else if (chbuf == "\"") dest += "&quot;";
  else dest += chbuf;
};

/* コメント文 (C Style) */
var comment = function() {
  dest += cl_com + "/*";
  while (getnext()) {
    if (chbuf == "*") {
      dest += chbuf;
      if (!getnext()) return;
      if (chbuf == "/") {
        dest += chbuf + cl_end;
        return;
      } else if (chbuf == "*") {
        ungetnext();
      } else normal();          
    } else normal();
  }
  dest += cl_end;
};

/* コメント文 (C++ Style) */
var comment_line = function() {
  dest += cl_com + "//";
  while (getnext()) {
    if (chbuf == "\n") {
      dest += cl_end + "\n";
      return;
    } else normal();          
  }
  dest += cl_end;
};

/* 文字列定数 */
var string = function(c) {
  var escape = false;
  if (c == "\"")
    dest += cl_str + "&quot;";
  else
    dest += cl_str + c;
  while (getnext()) {
    if (escape == 0 && chbuf == c) {
      if (c == "\"")
        dest += "&quot;" + cl_end;
      else
        dest += c + cl_end;
      return;
    } else if (chbuf == "\\") {
      escape = !escape;
      dest += chbuf;
    } else {
      escape = false;
      normal();
    }
  }
  dest += cl_end;
};

/* 予約語を探す */
var symbol = function() {
  var buf = "";
  buf += chbuf;
  if (!getnext()) {
    dest += buf;
    return;
  }
  while (chbuf.match(/[\w]/)) {
    buf += chbuf;
    if (!getnext()) break;
  }
  if (keys['_' + buf])
    dest += cl_key + buf + cl_end;
  else
    dest += buf;  
  if (!error) ungetnext();
};

/* 最初の文字を判定して処理を分岐する */
var getsym = function() {
  if (!getnext()) return;
  if (chbuf == "/") {
    if (!getnext()) {
      dest += "/";
      return;
    }
    if (chbuf == "*")
      comment();
    else if (chbuf == "/")
      comment_line();
    else {
      dest += "/";
      ungetnext();
    }
  } else if (chbuf == "\"" || chbuf == "'") {
    string(chbuf);
  } else if (chbuf.match(/[\w]/)) {
    symbol();
  } else if (chbuf == "=" || chbuf == "(") {
    normal();
    while (getnext()) {
      if (chbuf.match(/\s/)) {
        normal();
      } else if (chbuf == "/") {
          string(chbuf);
          break;
      } else {
        ungetnext();
        break;
      }
    }
  } else {
    normal();
  }
};

/* 解析 */
this.parse = function(str) {
  cl_key = this.color_keyword;
  cl_com = this.color_comment;
  cl_str = this.color_string;
  cl_end = this.color_end;
  src = str.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
  dest = "<pre>";
  pos = error = 0;
  while (!error) getsym();
  return dest + "</pre>";
};
//////////////////////////////////////////////////////////
}