CB-12546: emulator specs.

This commit is contained in:
filmaj
2017-03-14 13:12:57 -07:00
parent eb6ada8091
commit 6395eda0c8
24 changed files with 655 additions and 446 deletions
Generated Vendored
+132 -85
View File
@@ -2,21 +2,21 @@
//[4a] NameChar ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
//[5] Name ::= NameStartChar (NameChar)*
var nameStartChar = /[A-Z_a-z\xC0-\xD6\xD8-\xF6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]///\u10000-\uEFFFF
var nameChar = new RegExp("[\\-\\.0-9"+nameStartChar.source.slice(1,-1)+"\u00B7\u0300-\u036F\\u203F-\u2040]");
var nameChar = new RegExp("[\\-\\.0-9"+nameStartChar.source.slice(1,-1)+"\\u00B7\\u0300-\\u036F\\u203F-\\u2040]");
var tagNamePattern = new RegExp('^'+nameStartChar.source+nameChar.source+'*(?:\:'+nameStartChar.source+nameChar.source+'*)?$');
//var tagNamePattern = /^[a-zA-Z_][\w\-\.]*(?:\:[a-zA-Z_][\w\-\.]*)?$/
//var handlers = 'resolveEntity,getExternalSubset,characters,endDocument,endElement,endPrefixMapping,ignorableWhitespace,processingInstruction,setDocumentLocator,skippedEntity,startDocument,startElement,startPrefixMapping,notationDecl,unparsedEntityDecl,error,fatalError,warning,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,comment,endCDATA,endDTD,endEntity,startCDATA,startDTD,startEntity'.split(',')
//S_TAG, S_ATTR, S_EQ, S_V
//S_ATTR_S, S_E, S_S, S_C
//S_TAG, S_ATTR, S_EQ, S_ATTR_NOQUOT_VALUE
//S_ATTR_SPACE, S_ATTR_END, S_TAG_SPACE, S_TAG_CLOSE
var S_TAG = 0;//tag name offerring
var S_ATTR = 1;//attr name offerring
var S_ATTR_S=2;//attr name end and space offer
var S_ATTR_SPACE=2;//attr name end and space offer
var S_EQ = 3;//=space?
var S_V = 4;//attr value(no quot value only)
var S_E = 5;//attr value end and no space(quot end)
var S_S = 6;//(attr value end || tag end ) && (space offer)
var S_C = 7;//closed el<el />
var S_ATTR_NOQUOT_VALUE = 4;//attr value(no quot value only)
var S_ATTR_END = 5;//attr value end and no space(quot end)
var S_TAG_SPACE = 6;//(attr value end || tag end ) && (space offer)
var S_TAG_CLOSE = 7;//closed el<el />
function XMLReader(){
@@ -33,7 +33,7 @@ XMLReader.prototype = {
}
}
function parse(source,defaultNSMapCopy,entityMap,domBuilder,errorHandler){
function fixedFromCharCode(code) {
function fixedFromCharCode(code) {
// String.prototype.fromCharCode does not supports
// > 2 bytes unicode chars directly
if (code > 0xffff) {
@@ -76,7 +76,7 @@ function parse(source,defaultNSMapCopy,entityMap,domBuilder,errorHandler){
}
var lineStart = 0;
var lineEnd = 0;
var linePattern = /.+(?:\r\n?|\n)|.*$/g
var linePattern = /.*(?:\r\n?|\n)|.*$/g
var locator = domBuilder.locator;
var parseStack = [{currentNSMap:defaultNSMapCopy}]
@@ -87,7 +87,7 @@ function parse(source,defaultNSMapCopy,entityMap,domBuilder,errorHandler){
var tagStart = source.indexOf('<',start);
if(tagStart<0){
if(!source.substr(start).match(/^\s*$/)){
var doc = domBuilder.document;
var doc = domBuilder.doc;
var text = doc.createTextNode(source.substr(start));
doc.appendChild(text);
domBuilder.currentElement = text;
@@ -102,16 +102,36 @@ function parse(source,defaultNSMapCopy,entityMap,domBuilder,errorHandler){
var end = source.indexOf('>',tagStart+3);
var tagName = source.substring(tagStart+2,end);
var config = parseStack.pop();
var localNSMap = config.localNSMap;
if(config.tagName != tagName){
errorHandler.fatalError("end tag name: "+tagName+' is not match the current start tagName:'+config.tagName );
}
domBuilder.endElement(config.uri,config.localName,tagName);
if(localNSMap){
for(var prefix in localNSMap){
domBuilder.endPrefixMapping(prefix) ;
}
if(end<0){
tagName = source.substring(tagStart+2).replace(/[\s<].*/,'');
//console.error('#@@@@@@'+tagName)
errorHandler.error("end tag name: "+tagName+' is not complete:'+config.tagName);
end = tagStart+1+tagName.length;
}else if(tagName.match(/\s</)){
tagName = tagName.replace(/[\s<].*/,'');
errorHandler.error("end tag name: "+tagName+' maybe not complete');
end = tagStart+1+tagName.length;
}
//console.error(parseStack.length,parseStack)
//console.error(config);
var localNSMap = config.localNSMap;
var endMatch = config.tagName == tagName;
var endIgnoreCaseMach = endMatch || config.tagName&&config.tagName.toLowerCase() == tagName.toLowerCase()
if(endIgnoreCaseMach){
domBuilder.endElement(config.uri,config.localName,tagName);
if(localNSMap){
for(var prefix in localNSMap){
domBuilder.endPrefixMapping(prefix) ;
}
}
if(!endMatch){
errorHandler.fatalError("end tag name: "+tagName+' is not match the current start tagName:'+config.tagName );
}
}else{
parseStack.push(config)
}
end++;
break;
// end elment
@@ -124,33 +144,40 @@ function parse(source,defaultNSMapCopy,entityMap,domBuilder,errorHandler){
end = parseDCC(source,tagStart,domBuilder,errorHandler);
break;
default:
locator&&position(tagStart);
var el = new ElementAttributes();
var currentNSMap = parseStack[parseStack.length-1].currentNSMap;
//elStartEnd
var end = parseElementStartPart(source,tagStart,el,entityReplacer,errorHandler);
var end = parseElementStartPart(source,tagStart,el,currentNSMap,entityReplacer,errorHandler);
var len = el.length;
if(locator){
if(len){
//attribute position fixed
for(var i = 0;i<len;i++){
var a = el[i];
position(a.offset);
a.offset = copyLocator(locator,{});
}
}
position(end);
}
if(!el.closed && fixSelfClosed(source,end,el.tagName,closeMap)){
el.closed = true;
if(!entityMap.nbsp){
errorHandler.warning('unclosed xml attribute');
}
}
appendElement(el,domBuilder,parseStack);
if(locator && len){
var locator2 = copyLocator(locator,{});
//try{//attribute position fixed
for(var i = 0;i<len;i++){
var a = el[i];
position(a.offset);
a.locator = copyLocator(locator,{});
}
//}catch(e){console.error('@@@@@'+e)}
domBuilder.locator = locator2
if(appendElement(el,domBuilder,currentNSMap)){
parseStack.push(el)
}
domBuilder.locator = locator;
}else{
if(appendElement(el,domBuilder,currentNSMap)){
parseStack.push(el)
}
}
if(el.uri === 'http://www.w3.org/1999/xhtml' && !el.closed){
@@ -160,8 +187,10 @@ function parse(source,defaultNSMapCopy,entityMap,domBuilder,errorHandler){
}
}
}catch(e){
errorHandler.error('element parse error: '+e);
errorHandler.error('element parse error: '+e)
//errorHandler.error('element parse error: '+e);
end = -1;
//throw e;
}
if(end>start){
start = end;
@@ -181,7 +210,7 @@ function copyLocator(f,t){
* @see #appendElement(source,elStartEnd,el,selfClosed,entityReplacer,domBuilder,parseStack);
* @return end of the elementStartPart(end of elementEndPart for selfClosed el)
*/
function parseElementStartPart(source,start,el,entityReplacer,errorHandler){
function parseElementStartPart(source,start,el,currentNSMap,entityReplacer,errorHandler){
var attrName;
var value;
var p = ++start;
@@ -193,7 +222,7 @@ function parseElementStartPart(source,start,el,entityReplacer,errorHandler){
if(s === S_ATTR){//attrName
attrName = source.slice(start,p);
s = S_EQ;
}else if(s === S_ATTR_S){
}else if(s === S_ATTR_SPACE){
s = S_EQ;
}else{
//fatalError: equal must after attrName or space after attrName
@@ -202,25 +231,30 @@ function parseElementStartPart(source,start,el,entityReplacer,errorHandler){
break;
case '\'':
case '"':
if(s === S_EQ){//equal
if(s === S_EQ || s === S_ATTR //|| s == S_ATTR_SPACE
){//equal
if(s === S_ATTR){
errorHandler.warning('attribute value must after "="')
attrName = source.slice(start,p)
}
start = p+1;
p = source.indexOf(c,start)
if(p>0){
value = source.slice(start,p).replace(/&#?\w+;/g,entityReplacer);
el.add(attrName,value,start-1);
s = S_E;
s = S_ATTR_END;
}else{
//fatalError: no end quot match
throw new Error('attribute value no end \''+c+'\' match');
}
}else if(s == S_V){
}else if(s == S_ATTR_NOQUOT_VALUE){
value = source.slice(start,p).replace(/&#?\w+;/g,entityReplacer);
//console.log(attrName,value,start,p)
el.add(attrName,value,start);
//console.dir(el)
errorHandler.warning('attribute "'+attrName+'" missed start quot('+c+')!!');
start = p+1;
s = S_E
s = S_ATTR_END
}else{
//fatalError: no equal before
throw new Error('attribute value must after "="');
@@ -230,14 +264,14 @@ function parseElementStartPart(source,start,el,entityReplacer,errorHandler){
switch(s){
case S_TAG:
el.setTagName(source.slice(start,p));
case S_E:
case S_S:
case S_C:
s = S_C;
case S_ATTR_END:
case S_TAG_SPACE:
case S_TAG_CLOSE:
s =S_TAG_CLOSE;
el.closed = true;
case S_V:
case S_ATTR_NOQUOT_VALUE:
case S_ATTR:
case S_ATTR_S:
case S_ATTR_SPACE:
break;
//case S_EQ:
default:
@@ -247,30 +281,36 @@ function parseElementStartPart(source,start,el,entityReplacer,errorHandler){
case ''://end document
//throw new Error('unexpected end of input')
errorHandler.error('unexpected end of input');
if(s == S_TAG){
el.setTagName(source.slice(start,p));
}
return p;
case '>':
switch(s){
case S_TAG:
el.setTagName(source.slice(start,p));
case S_E:
case S_S:
case S_C:
case S_ATTR_END:
case S_TAG_SPACE:
case S_TAG_CLOSE:
break;//normal
case S_V://Compatible state
case S_ATTR_NOQUOT_VALUE://Compatible state
case S_ATTR:
value = source.slice(start,p);
if(value.slice(-1) === '/'){
el.closed = true;
value = value.slice(0,-1)
}
case S_ATTR_S:
if(s === S_ATTR_S){
case S_ATTR_SPACE:
if(s === S_ATTR_SPACE){
value = attrName;
}
if(s == S_V){
if(s == S_ATTR_NOQUOT_VALUE){
errorHandler.warning('attribute "'+value+'" missed quot(")!!');
el.add(attrName,value.replace(/&#?\w+;/g,entityReplacer),start)
}else{
errorHandler.warning('attribute "'+value+'" missed value!! "'+value+'" instead!!')
if(currentNSMap[''] !== 'http://www.w3.org/1999/xhtml' || !value.match(/^(?:disabled|checked|selected)$/i)){
errorHandler.warning('attribute "'+value+'" missed value!! "'+value+'" instead!!')
}
el.add(value,value,start)
}
break;
@@ -287,64 +327,68 @@ function parseElementStartPart(source,start,el,entityReplacer,errorHandler){
switch(s){
case S_TAG:
el.setTagName(source.slice(start,p));//tagName
s = S_S;
s = S_TAG_SPACE;
break;
case S_ATTR:
attrName = source.slice(start,p)
s = S_ATTR_S;
s = S_ATTR_SPACE;
break;
case S_V:
case S_ATTR_NOQUOT_VALUE:
var value = source.slice(start,p).replace(/&#?\w+;/g,entityReplacer);
errorHandler.warning('attribute "'+value+'" missed quot(")!!');
el.add(attrName,value,start)
case S_E:
s = S_S;
case S_ATTR_END:
s = S_TAG_SPACE;
break;
//case S_S:
//case S_TAG_SPACE:
//case S_EQ:
//case S_ATTR_S:
//case S_ATTR_SPACE:
// void();break;
//case S_C:
//case S_TAG_CLOSE:
//ignore warning
}
}else{//not space
//S_TAG, S_ATTR, S_EQ, S_V
//S_ATTR_S, S_E, S_S, S_C
//S_TAG, S_ATTR, S_EQ, S_ATTR_NOQUOT_VALUE
//S_ATTR_SPACE, S_ATTR_END, S_TAG_SPACE, S_TAG_CLOSE
switch(s){
//case S_TAG:void();break;
//case S_ATTR:void();break;
//case S_V:void();break;
case S_ATTR_S:
errorHandler.warning('attribute "'+attrName+'" missed value!! "'+attrName+'" instead!!')
//case S_ATTR_NOQUOT_VALUE:void();break;
case S_ATTR_SPACE:
var tagName = el.tagName;
if(currentNSMap[''] !== 'http://www.w3.org/1999/xhtml' || !attrName.match(/^(?:disabled|checked|selected)$/i)){
errorHandler.warning('attribute "'+attrName+'" missed value!! "'+attrName+'" instead2!!')
}
el.add(attrName,attrName,start);
start = p;
s = S_ATTR;
break;
case S_E:
case S_ATTR_END:
errorHandler.warning('attribute space is required"'+attrName+'"!!')
case S_S:
case S_TAG_SPACE:
s = S_ATTR;
start = p;
break;
case S_EQ:
s = S_V;
s = S_ATTR_NOQUOT_VALUE;
start = p;
break;
case S_C:
case S_TAG_CLOSE:
throw new Error("elements closed character '/' and '>' must be connected to");
}
}
}
}//end outer switch
//console.log('p++',p)
p++;
}
}
/**
* @return end of the elementStartPart(end of elementEndPart for selfClosed el)
* @return true if has new namespace define
*/
function appendElement(el,domBuilder,parseStack){
function appendElement(el,domBuilder,currentNSMap){
var tagName = el.tagName;
var localNSMap = null;
var currentNSMap = parseStack[parseStack.length-1].currentNSMap;
//var currentNSMap = parseStack[parseStack.length-1].currentNSMap;
var i = el.length;
while(i--){
var a = el[i];
@@ -383,7 +427,7 @@ function appendElement(el,domBuilder,parseStack){
if(prefix === 'xml'){
a.uri = 'http://www.w3.org/XML/1998/namespace';
}if(prefix !== 'xmlns'){
a.uri = currentNSMap[prefix]
a.uri = currentNSMap[prefix || '']
//{console.log('###'+a.qName,domBuilder.locator.systemId+'',currentNSMap,a.uri)}
}
@@ -412,7 +456,8 @@ function appendElement(el,domBuilder,parseStack){
}else{
el.currentNSMap = currentNSMap;
el.localNSMap = localNSMap;
parseStack.push(el);
//parseStack.push(el);
return true;
}
}
function parseHtmlSpecialContent(source,elStartEnd,tagName,entityReplacer,domBuilder){
@@ -442,7 +487,11 @@ function fixSelfClosed(source,elStartEnd,tagName,closeMap){
var pos = closeMap[tagName];
if(pos == null){
//console.log(tagName)
pos = closeMap[tagName] = source.lastIndexOf('</'+tagName+'>')
pos = source.lastIndexOf('</'+tagName+'>')
if(pos<elStartEnd){//忘记闭合
pos = source.lastIndexOf('</'+tagName)
}
closeMap[tagName] =pos
}
return pos<elStartEnd;
//}
@@ -533,7 +582,7 @@ ElementAttributes.prototype = {
},
length:0,
getLocalName:function(i){return this[i].localName},
getOffset:function(i){return this[i].offset},
getLocator:function(i){return this[i].locator},
getQName:function(i){return this[i].qName},
getURI:function(i){return this[i].uri},
getValue:function(i){return this[i].value}
@@ -580,7 +629,5 @@ function split(source,start){
}
}
if(typeof require == 'function'){
exports.XMLReader = XMLReader;
}
exports.XMLReader = XMLReader;