⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 syntax-parser.js

📁 原名JSPackager
💻 JS
字号:
var ie5 = "test".replace(/\w+/,'$&') == "$&";

/**
 * @public
 * @constructor
 * @param <String> source
 */
function SyntaxParser(source){
  this.initialize(source);
}
function cloneObject(src){
  var dest = {};
  for(var n in src){
    dest[n] = src[n];
  }
  return dest;
}
/**
 * @protected
 */
SyntaxParser.prototype.initialize = function(source){
  this.source = source;
  this.depths = [];
  this.anchors = [];
  this.partitionerMap = cloneObject(this.partitionerMap);
  this.rendererMap = cloneObject(this.rendererMap);
  this.depVisitorMap = cloneObject(this.depVisitorMap);
}

/**
 * 设置分区渲染函数表
 */
SyntaxParser.prototype.setRendererMap = function(group){
  this.rendererMap = {};
  for(var n in group){
    n = n || this.defaultType;
    var v = group[n];
    if(v instanceof Function){//is Function
      this.rendererMap[n] = v;
    }else{
      if(v instanceof Array){
        v = '(\\b'+v.join('\\b|\\b') + '\\b)';
      }
      var reg =  new RegExp(v,'g');
      this.rendererMap[n] = this.buildRenderer(reg,"<b class='xidea--syntax-keyword xidea--syntax-$1'>$1</b>");
    }
  }
}
SyntaxParser.prototype.buildRenderer = function(regexp,str){
  return function(text){
    return text.replace(regexp,str);
  };
}
//IE5 does not support $&; and replacer function


/**
 * 设置分区表
 */
SyntaxParser.prototype.setPartitionerMap = function(group){
  this.partitionerMap = {};
  function build(ps){
    if(ps.exec){//is RegExp
      return ps;
    }else{
      if(ps instanceof Array){
        var ps = ps.join('|');
      }
      return new RegExp(ps,'gm');
    }
  }
  
  for(var n in group){
    this.partitionerMap[n || this.defaultType] = build(group[n])
  }
  
}

/**
 * parse the code
 * @protected
 */
SyntaxParser.prototype.parse = function(){
  if(!this.lines){
    this.lines = [];
    var lreg = // /\r\n|\n|\r/g;//
      new RegExp("\\r\\n|\\n|\\r",'g');
    var begin = 0,lm;
    while(lm=lreg.exec(this.source)){
      this.lines.push({begin:begin,end:lm.index});
      begin = lm.index+lm[0].length;
    }
    if(begin<this.source.length){
      this.lines.push({begin:begin,end:this.source.length});
    }
    //alert(this.lines.length)
    this.partitions = this.buildPartitions();
  }
}

/**
 * private
 */
SyntaxParser.prototype.defaultType = "code";


SyntaxParser.prototype.guessType = function(){
  for(var n in this.partitionerMap){
    if(this.partitionerMap[n].test(p)){
      return n;
    }
  }
  return this.defaultType;
};
function Partition(value,type,begin,end){
  this.value = value;
  this.type = type;
  this.begin = begin;
  this.end = end;
}
Partition.prototype.toString = function(){
  return '{value:'+this.value+
         ',type:'+this.type+
         ',begin:'+this.begin+
         ',end:'+this.end+'}\n';
         
}
/**
 * parse partitions
 * @protected
 */
SyntaxParser.prototype.parsePartitions = function(){
  var exp = [];
  for(var n in this.partitionerMap){
    exp.push(this.partitionerMap[n].source);
  }
  exp = new RegExp(exp.join('|'),"gm");
  var match,ps=[],s = this.source;
  while(match = exp.exec(s)){
    var token = match[0];
    var type = this.guessType(token);
    ps.push(new Partition(token,type,match.index,match.index + token.length));
  }
  return ps;
};
/**
 * build partitions(fill blank part and compute depths)
 * @protected
 */
SyntaxParser.prototype.buildPartitions = function(){
  var nps = [],pos = 0,dep = 0,ps = this.parsePartitions();
  for(var i = 0;i<ps.length;i++){
    var p = ps[i];
    if(p.begin >pos){
      var bp = new Partition(this.source.substring(pos,p.begin),this.defaultType,pos,p.begin);
      dep = this.computeDepth(bp,dep);
      nps.push(bp);
    }
    dep = this.computeDepth(p,dep);
    nps.push(p);
    pos = p.end;
  }
  if(pos<this.source.length){
    var p = new Partition(this.source.substr(pos),this.defaultType,pos,this.source.length);
    dep = this.computeDepth(p,dep);
    nps.push(p);
  }
  return nps;
}




/**
 * compute depths.
 * default implements is scan the code for '{'|'}',if '{' <b>++depth</b> else <b>depth--</b>
 * @protected
 */
SyntaxParser.prototype.computeDepth = function(p,dep){
  switch(p.type){
    case 'code':
      var reg = new RegExp("\{|\}",'g');
      var match, code = p.value;
      while(match = reg.exec(code)){
        if(match[0] == '{'){
          this.depths.push({position:p.begin+match.index,
            preDepth:dep,minDepth:dep++,nextDepth:dep,
            type:'open'});
        }else{
          this.depths.push({position:p.begin+match.index,
            preDepth:dep,minDepth:--dep,nextDepth:dep,
            type:'close'});
        }
      }
      break;
    case 'muti-comment':
    case 'document':
      this.depths.push({position:p.begin,
        preDepth:dep,minDepth:dep++,nextDepth:dep,
        type:'open'});
      this.depths.push({position:p.end-1,
        preDepth:dep,minDepth:--dep,nextDepth:dep,
        type:'close'});
      break;
  }
  return dep;
};




SyntaxParser.prototype.buildLineIterator = function(){
  if(this.partitions.length == 0){
    this.parse();
  }
  return new LineIterator(this);
};
/**
 * @protected
 * @constructor
 * @param <String> sourceParser
 */
function LineIterator(sourceParser){
  this.parser = sourceParser;
  this.source = sourceParser.source;
  this.partitions = sourceParser.partitions;
  this.lines = sourceParser.lines;
  this.depths = sourceParser.depths;
  this.anchors = sourceParser.anchors;
  this.depth = 0;
  this.nextDepth = 0;
  this.depthStack = [-1];
  this.depthStart = -1
  this.partitionIndex = 0;
  this.lineIndex = 0;
  this.depthIndex = 0;
  this.anchorsIndex = 0;
}
LineIterator.prototype.hasNext = function(){
  return (this.partitions[this.partitionIndex] && this.lines[this.lineIndex]);
};

LineIterator.prototype.next = function(){
  var p = this.partitions[this.partitionIndex];
  var l = this.lines[this.lineIndex];
  //alert(l.begin+"/"+l.end)
  if(!p || !l){return null}
  try{
    //dell with depths
    var d = this.depths[this.depthIndex];
    if(d != null){
      if(d.position<l.end){
        this.depth = d.minDepth;
        while(d = this.depths[++this.depthIndex]){
          if(d.position<l.end){
            this.depth = Math.min(this.depth,d.minDepth);
          }else{
            break;
          }
        }
        if(d){
          this.nextDepth = d.preDepth;
        }else{
          this.nextDepth = 0;
          this.depth = 0;
          this.depthStack.length = 0;
          this.depthStart = -2;
        }
      }else{
        this.nextDepth = this.depth = d.preDepth;
      }
    }
    //dell with depth stack
    var i = this.depth - this.depthStack.length+1;
    if(i>0){
      while(i-->0){
        this.depthStack.push(this.lineIndex);
        this.depthStart = this.lineIndex;
      }
    }else if(i<0){
      this.depthStack.length = this.depth+1;
      this.depthStart = this.depthStack[this.depth];
    }
    //dell with anchors
    var a = this.anchors[this.anchorsIndex];
    this.anchor = "";
    if(a && a.position<l.end){
      this.anchor = "";
      do{
        this.anchor += "<a name=\""+a.name+"\" />";
        a = this.anchors[++this.anchorsIndex];
      }while(a && a.position<l.end)
    }
    //dell with line;
    if(p.end>=l.end){
      return this.render(l.begin,l.end,p.type);
    }else{
       var buf = [];
       var i = l.begin;
       while(p.end<l.end){
         buf.push(this.render(i,i=p.end,p.type));
         p = this.partitions[++this.partitionIndex];
       }
       buf.push(this.render(i,l.end,p.type));
       return buf.join('');
    }

  }finally{
    this.lineIndex++; 
  }
};

LineIterator.prototype.render = function(b,e,type){
  if(e>b){
    var text = this.source.substring(b,e);
    text = this.encodeText(text);
    //.replace(/ /g,"&nbsp;").replace(/\t/g,"&nbsp;&nbsp;&nbsp;&nbsp;");
    var renderer = this.parser.rendererMap[type];
    if(renderer){
      text = renderer.call(this.parser,text);
      //text.replace(/@([a-zA-Z\-]+)/,this.tagReplacer);
    }
    return "<span class='xidea--syntax-"+type+"'>"+text+"</span>";
  }else{
    return '';
  }
};

LineIterator.prototype.encodeText = function(str){
  if(str){
    return str.replace(/[\r\n]/g,'').
      replace(/&/g,'&amp;').
      replace(/>/g,'&gt;').
      replace(/</g,'&lt;');
  }
  return str;
};

function ECMAParser(source){
  this.initialize(source);
}
$JSI.extend(ECMAParser,SyntaxParser);
//ECMAParser.prototype = new SyntaxParser();

/**
 * keywords Regexp.
 * default is for javascript 
 * @protected
 */
ECMAParser.prototype.setRendererMap({
  'code':['abstract','boolean','break','byte','case','catch','char','class','const','continue','debugger',
    'default','delete','do','double','else','enum','export','extends','false','final','finally','float',
    'for','function','goto','if','implements','import','in','instanceof','int','interface','long','native',
    'new','null','package','private','protected','prototype','public','return','short','static','super','switch',
    'synchronized','this','throw','throws','transient','true','try','typeof','var','void','volatile','while','with'],
  'document':ECMAParser.prototype.buildRenderer(/@([\w-_\.\d]+)/g,"<b class='xidea--syntax-tag xidea--syntax-$1'>@$1</b>")
}
);

/**
 * partitions Regexp.
 * default is for javascript 
 * @protected
 */
ECMAParser.prototype.setPartitionerMap(
{
      'document':'/\\*\\*(?:[^\\*]|\\*[^/])*\\*/'
      ,'muti-comment':'/\\*(?:[^\\*]|\\*[^/])*\\*/'//muti-comment
      ,'comment':'//.*$'                    //single-comment
      ,'regexp':'/(?:\\\\.|[^/\\n\\r])+/'  //regexp
      ,'string':['"(?:\\\\.|[^"\\n\\r])*"',"'(?:\\\\.|[^'\\n\\r])*'"]  //string
      ,'preprocessor':'^\\s*#.*'             //process
}
);


/**
 * 针对JavaScript优化
 * guess the type of given partition.
 * default is for javascript 
 * @protected
 */
ECMAParser.prototype.guessType = function(p){
  var type = "";
  switch(p.charAt(0)){
    case '/':
      var c = p.charAt(1);
      if(c == '/'){
        type = "comment";
      }else if(c == '*'){
        if(p.charAt(2) == '*' && p.charAt(3) != '/'){
          type = "document";
        }else{
          type = "muti-comment";
        }
      }else{
        type = "regexp";
      }
      break;
    case '\'':
    case '"':
      type = "string";
      break;
    case ' ':
    case '#':
      type = "preprocessor";
      break;
  }
  return type;
};

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -