js语法检查器


将以下代码拷贝到新的HTML文件中打开即可看到效果!
1 <!DOCTYPE html> 2 <html lang="en" xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <meta charset="utf-8" /> 5 <title>JS语法检查器</title> 6 <style> 7 .js-color-reservedword { 8 color: #0823fc; 9 } 10 .js-color-identifier { 11 color: #ff8013; 12 } 13 .js-color-exception { 14 text-decoration: underline; 15 color: red; 16 } 17 .js-color-numericliteral { 18 color: #6df407; 19 } 20 .js-color-stringliteral { 21 color: #fc9090; 22 } 23 .js-color-comment { 24 color: green; 25 } 26 .js-color-functionname { 27 color: #f8f408; 28 } 29 .js-color-punctuator { 30 color: #e804fa; 31 } 32 .js-color-regularexpressionliteral { 33 color: #73b2ee; 34 } 35 .js-color-linecount { 36 color: pink; 37 } 38 .js-code-line-border { 39 border: 1px solid #cbeeb0; 40 } 41 .code-text, .code-div { 42 width: 600px; 43 height: 600px; 44 } 45 div, span { 46 margin: 0px; 47 padding: 0px; 48 } 49 pre{ 50 margin: 0; 51 padding: 0; 52 display: block; 53 } 54 .js-code-edit, textarea { 55 font-size: 15px; 56 color: black; 57 background-color: white; 58 width: 49%; 59 height: 600px; 60 float: left; 61 border: none; 62 outline: 1px solid black; 63 overflow: auto; 64 margin-left: 0.8%; 65 } 66 button { 67 width: 240px; 68 height: 50px; 69 margin-top: 20px; 70 } 71 </style> 72 </head> 73 <body> 74 <textarea spellcheck="false"> 75 function paintAST(ast){ 76 var result = "<pre>" + _paintAST(ast) + "</pre>"; 77 return result.replace(/<pre><\/pre>/, '<pre><br></pre>'); 78 function _paintAST(ast){ 79 var str = ''; 80 for(var name in ast){ 81 if(_typeof(ast[name], 'Object') && ast[name].value){ 82 if(ast[name].type == 'LineTerminator'){ str += ast[name].value.replace(/\s/g, '</pre><pre>'); } 83 else{ 84 var className = 'js-color-' + ast[name].type.toLowerCase(), 85 value = ast[name].value.replace(/</g, '<').replace(/>/g, '>'); 86 str += '<span class="' + className +'" ' + (ast[name].msg? 'title="' + ast[name].msg + '"': '') +'>' + value + '</span>'; 87 } 88 } 89 else if(_typeof(ast[name], 'Array') || _typeof(ast[name], 'Object')){ str += _paintAST(ast[name]); } 90 } 91 return str; 92 } 93 function _typeof(obj, type){ 94 return Object.prototype.toString.call(obj).indexOf(type) > -1; 95 } 96 } 97 </textarea> 98 <div class="js-code-edit" spellcheck="false"></div> 99 <button>Test</button> 100 <script> 101 var btn = document.querySelector('button'); 102 document.querySelector('.js-code-edit').innerHTML = JsCodeEdit(document.querySelector('textarea').value); 103 btn.onclick = function (e) { 104 //var sTime = Date.now(); 105 document.querySelector('.js-code-edit').innerHTML = JsCodeEdit(document.querySelector('textarea').value); 106 //alert((Date.now() - sTime)); 107 } 108 function JsCodeEdit(string) { 109 var ast = parserJSCode(string); 110 return paintAST(ast);//将表达式树转换成HTML 111 return printAST(ast);//返回表达式树 112 } 113 function printAST(ast) { 114 return JSON.stringify(ast); 115 } 116 function paintAST(ast){ 117 var result = "<pre>" + _paintAST(ast) + "</pre>"; 118 return result.replace(/<pre><\/pre>/, '<pre><br></pre>'); 119 function _paintAST(ast){ 120 var str = ''; 121 for(var name in ast){ 122 if(_typeof(ast[name], 'Object') && ast[name].value){ 123 if(ast[name].type == 'LineTerminator'){ str += ast[name].value.replace(/\s/g, '</pre><pre>'); } 124 else{ 125 var className = 'js-color-' + ast[name].type.toLowerCase(), 126 value = ast[name].value.replace(/</g, '<').replace(/>/g, '>'); 127 str += '<span class="' + className +'" ' + (ast[name].msg? 'title="' + ast[name].msg + '"': '') +'>' + value + '</span>'; 128 } 129 } 130 else if(_typeof(ast[name], 'Array') || _typeof(ast[name], 'Object')){ str += _paintAST(ast[name]); } 131 } 132 return str; 133 } 134 function _typeof(obj, type){ 135 return Object.prototype.toString.call(obj).indexOf(type) > -1; 136 } 137 } 138 function parserJSCode(string) { 139 if (!string || typeof string != 'string') { return { AST: { type: 'Program', body: [] } }; } 140 var globalVariable = { strictModel: false, currInstance: '' }; 141 var AST = { type: 'Program', body: [] }, i = 0; 142 var PARSER_FINSH = 'Parser js code is finshed!'; 143 var startFun = new Function(); 144 try{ startFun.program(AST.body); 145 } 146 catch(e){ 147 if(e != PARSER_FINSH){ console.error(e); } 148 } 149 return AST; 150 function peek(parent, getReg) { 151 if(eol()){ throw PARSER_FINSH; } 152 var haveLineTerminator = false; 153 do{ 154 var space = getSpace(), 155 terminator = getLineTerminator(), 156 comm = comment(); 157 pushItem(parent, space), pushItem(parent, terminator), pushItem(parent, comm); 158 if(!space && ! terminator && !comm){ break; } 159 }while(!eol()); 160 if(eol()){ throw PARSER_FINSH; } 161 var returnObj = identifierName() || stringLiteral() || numericLiteral() || punctuator() || 162 (getReg && regularExpressionLiteral()) || divPunctuator() || unknowToken(); 163 returnObj.haveLineTerminator = haveLineTerminator; 164 return returnObj; 165 166 function stringLiteral() { 167 var str = { type: '', value: '', msg: '' }; 168 if (/['"']/g.test(string[i])) { 169 str.type = 'StringLiteral', str.value += string[i]; 170 var ch = string[i]; 171 for (i++; !eol() && string[i] != ch && !isLineTerminator(string[i]) ; i++) { 172 if (string[i] == '\\') { 173 str.value += string[i] + (string[++i] ? string[i] : ''); 174 var len = (string[i] == 'u' ? 4 : string[i] == 'x' ? 2 : 0) 175 for (i++; !eol() && len > 0 && string[i] != ch; len--, i++) { 176 str.value += string[i]; 177 if (!isHex(string[i])) { str.msg = len == 2 ? 'Invalid Hex const!' : 'Invalid Unicode const!'; } 178 } 179 i--; 180 } 181 else { str.value += string[i]; } 182 } 183 if (string[i] == ch) { str.value += ch; i++; } 184 else { str.msg = 'add ' + ch + ' to end string!'; } 185 } 186 return str.value ? str : ''; 187 } 188 function identifierName() { 189 var identifier = { type: '', value: '', msg: '' }; 190 if (!(/[a-zA-Z_$\\]/g.test(string[i]))) { return ''; } 191 identifier.type = 'IdentifierName', identifier.value += string[i] == '\\' ? '' : string[i]; 192 for (string[i] == '\\' ? i : i++; !eol() && /[a-zA-Z_$\d\\]/g.test(string[i]) ; i++) { 193 identifier.value += string[i]; 194 if (string[i] == '\\') { 195 if (string[i + 1] != 'u') { identifier.msg = 'Invalid Unicode!'; continue; } 196 identifier.value += string[++i]; 197 var count = 0; 198 for (i++; !eol() && isHex(string[i]) ; count++, i++) { identifier.value += string[i]; } 199 i--; 200 identifier.msg = (count < 4 ? 'Invalid Unicode!' : ''); 201 } 202 } 203 if (identifier.value && isReservedWord(identifier.value)) { identifier.type = 'Reservedword'; } 204 else if (identifier.value) { identifier.type = 'Identifier'; } 205 return identifier.value ? identifier : ''; 206 } 207 function numericLiteral() { 208 var numeric = { type: '', value: '', msg: '' }; 209 //if (!(/[.\d+-]/g.test(string[i])) || (string[i] == '.' && !isDigit(string[i + 1]))) { return ''; } 210 //if(/[+-]/g.test(string[i])){ 211 //if (!(/[.\d]/g.test(string[i + 1])) || (string[i + 1] == '.' && !isDigit(string[i + 2]))) { return ''; } 212 //numeric.value += string[i++]; 213 //} 214 if (!(/[.\d]/g.test(string[i])) || (string[i] == '.' && !isDigit(string[i + 1]))) { return ''; } 215 numeric.type = 'NumericLiteral', numeric.value += string[i]; 216 if (string[i] == '0' && /[xX]/g.test(string[i + 1])) { 217 var hex = string[++i]; 218 for (i++; !eol() && isHex(string[i]) ; i++) { hex += string[i]; } 219 if (hex.length > 1) { numeric.value += hex; } 220 else { i--; } 221 return numeric.value ? numeric : ''; 222 } 223 var numericArr = ['', '', '', ''], firstZero = string[i] == '0'; 224 for (i++; !eol() && isDigit(string[i]) ; i++) { numericArr[0] += string[i]; } 225 if (string[i] == '.') { 226 numericArr[1] = '.'; 227 numeric.msg = (firstZero && numericArr[0] ? 'Invalid numeric!' : ''); 228 i++; 229 } 230 for (; !eol() && isDigit(string[i]) ; i++) { numericArr[2] += string[i]; } 231 if (/[eE]/g.test(string[i])) { 232 if (/[^\d+-]/g.test(string[i + 1])) { 233 numeric.value += numericArr.join(''); 234 return numeric.value ? numeric : ''; 235 } 236 else if (/[+-]/g.test(string[i + 1]) && !isDigit(string[i + 2])) { 237 numeric.value += numericArr.join(''); 238 return numeric.value ? numeric : ''; 239 } 240 numericArr[3] += string[i] + string[++i]; 241 for (i++; !eol() && isDigit(string[i]) ; i++) { numericArr[3] += string[i]; } 242 } 243 numeric.value += numericArr.join(''); 244 return numeric.value ? numeric : ''; 245 } 246 function punctuator() { 247 var punc = { type: '', value: '', msg: '' }; 248 if (/[\[\]{}().,;:\?~]/g.test(string[i])) { return { type: 'Punctuator', value: string[i++], msg: '' } } 249 var sI = i, str = ''; 250 str = string[i] + string[i + 1] + string[i + 2] + string[i + 3]; 251 if (str == '>>>=') { punc.value = str; } 252 else { 253 str = string[i] + string[i + 1] + string[i + 2]; 254 if (['===', '!==', '>>>', '<<=', '>>='].indexOf(str) > -1) { punc.value = str; } 255 else { 256 str = string[i] + string[i + 1]; 257 if (['<=', '>=', '==', '!=', '++', '--', '>>', '<<', '&&', '||', '+=', '-=', '*=', '%=', '&=', '|=', '^='].indexOf(str) > -1) { punc.value = str; } 258 else { 259 str = string[i]; 260 if (['=', '+', '-', '*', '%', '&', '|', '^', '!', '>', '<'].indexOf(str) > -1) { punc.value = str; } 261 else { str = ''; } 262 } 263 } 264 } 265 i += str.length; 266 if (punc.value) { punc.type = 'Punctuator'; } 267 return punc.value ? punc : ''; 268 } 269 function divPunctuator() { 270 if (string[i] == '/') { 271 if (string[++i] == '=') { i++; return { type: 'Punctuator', value: '/=', msg: '' }; } 272 return { type: 'Punctuator', value: '/', msg: '' }; 273 } 274 return false; 275 } 276 function regularExpressionLiteral() { 277 if (string[i] != '/' || /[*\/]/.test(string[i + 1]) || isLineTerminator(string[i + 1])) { return ''; } 278 return getRegExp(string[i]); 279 function getRegExp(ch) { 280 var regExp = { type: 'RegularExpressionLiteral', value: string[i++], msg: '' }; 281 while (!eol() && string[i] != '/' && string[i] != ch && !isLineTerminator(string[i])) { 282 if (string[i] == '\\') { 283 regExp.value += string[i++]; 284 if (isLineTerminator(string[i])) { regExp.msg = 'Error RegularExpressionLiteral'; break; } 285 regExp.value += string[i++]; 286 } 287 else if (/[\[\(]/g.test(string[i])) { 288 var ch = string[i] == '[' ? ']' : ')'; 289 var r = getRegExp(ch); 290 ch = '/'; 291 regExp.value += r.value; 292 regExp.msg = r.msg; 293 if (r.end) { return regExp; } 294 } 295 else { regExp.value += string[i++]; } 296 } 297 if ((ch == ']' && string[i] == ch) || (ch == ')' && string[i] == ch)) { regExp.value += string[i++] } 298 else if (string[i] == '/') { 299 regExp.value += string[i++] 300 while (!eol() && /[a-zA-Z\d$_]/g.test(string[i])) { 301 regExp.value += string[i] 302 if (!(/[gim]/g.test(string[i++]))) { regExp.msg = 'Invaild Character'; } 303 } 304 regExp.end = true; 305 } 306 else { regExp.msg = 'Error RegularExpressionLiteral'; regExp.end = true; } 307 return regExp; 308 } 309 } 310 function comment() { 311 var comment = { type: 'Comment', value: '', msg: '' }; 312 if (string[i] == '/' && string[i + 1] == '/') { 313 comment.value += '//';// comment.type = 'SingleLineComment'; 314 for (i += 2; !eol() && !isLineTerminator(string[i]) ; i++) { comment.value += string[i]; } 315 } 316 else if (string[i] == '/' && string[i + 1] == '*') { 317 comment.value += '/*';// comment.type = 'MuliteLineComment'; 318 for (i += 2; !eol() && (string[i] != '*' || string[i + 1] != '/') ; i++) { comment.value += string[i]; } 319 comment.value += eol() ? '' : '*/'; 320 i += 2; 321 } 322 return comment.value ? comment : ''; 323 } 324 function unknowToken(){ 325 return { type: 'UnknowToken', value: string[i++], msg: 'Exception UnknowToken!' }; 326 } 327 function getSpace(){ 328 var space = { type: 'Space', value: '', msg: '' }; 329 while(!eol() && isSpace(string[i])){ 330 space.value += string[i++]; 331 } 332 return space.value? space: ''; 333 } 334 function getLineTerminator(){ 335 var terminator = { type: 'LineTerminator', value: '', msg: '' }; 336 while(!eol() && isLineTerminator(string[i])){ 337 haveLineTerminator = true; 338 terminator.value += string[i++]; 339 } 340 return terminator.value ? terminator: ''; 341 } 342 } 343 function Expression(parent, p) { 344 this.expression = expression; 345 this.assignmentExpression = assignmentExpression; 346 this.leftHandSideExpression = leftHandSideExpression; 347 function primaryExpression(parent, p) { 348 if (p && equal(p.value, '/')) { i--; p = null; } 349 p = p ? p : peek(parent, true); 350 var op = isItemInArray(['NumericLiteral', 'StringLiteral', 'Identifier', 'RegularExpressionLiteral'], p.type) ? p.type : p.value; 351 switch (op) { 352 case 'this': pushItem(parent, p); break; 353 case 'true': 354 case 'false': pushItem(parent, p); break; 355 case 'null': pushItem(parent, p); break; 356 case 'Identifier': pushItem(parent, p); break; 357 case 'StringLiteral': 358 case 'RegularExpressionLiteral': 359 case 'NumericLiteral': pushItem(parent, p); break; 360 case '[': return arrayLiteral(parent, p); 361 case '{': return objectLiteral(parent, p); 362 case '(': return argument(parent, p, true); 363 default: return p;//return exception 364 } 365 } 366 function arrayLiteral(parent, p) { 367 var arrayLiteral = { type: 'ArrayLiteral', items: [] }; 368 parent.push(arrayLiteral), parent = arrayLiteral.items; 369 pushItem(parent, p); 370 do { 371 p = peek(parent); 372 if (equal(p.value, ',')) { p = pushItem(parent, p); } 373 else if (equal(p.value, ']')) { return pushItem(parent, p); } 374 else { 375 p = assignmentExpression(parent, p); 376 if(p){ 377 if(equal(p.value, ']')){ return pushItem(parent, p); } 378 else if (equal(p.value, ',')) { p = pushItem(parent, p); } 379 else{ p = pushItem(parent, p, 'Invalid Character!'); } 380 } 381 } 382 } 383 while (true); 384 } 385 //function elementList(){ } 386 function objectLiteral(parent, p) { 387 var obj = { type: 'ObjectLiteral', child: [] }; 388 parent.push(obj), parent = obj.child; 389 p = pushItem(parent, p) || peek(parent); 390 if(equal(p.value, '}')){ return pushItem(parent, p); } 391 else{ 392 do{ 393 p = propertyAssignment(parent, p) || peek(parent); 394 if(equal(p.value, ',')){ 395 p = pushItem(parent, p) || peek(parent); 396 if(equal(p.value, '}')){ return pushItem(parent, p); } 397 } 398 else if(equal(p.value, '}')){ return pushItem(parent, p); } 399 else{ p = pushItem(parent, p, 'Excepted }'); } 400 }while(true); 401 } 402 } 403 //function propertyNameAndValueList(parent, p) { } 404 function propertyAssignment(parent, p) { 405 var propertyName = ['Identifier', 'Reservedword', 'StringLiteral', 'NumericLiteral']; 406 p = p? p: peek(parent); 407 if(propertyName.indexOf(p.type) == -1){ p.msg = p.msg || 'Invalid Proerty Name!'; } 408 if(equal(p.value, 'get') || equal(p.value, 'set')){ return _GetAndSet(p.value, p); } 409 else{ 410 p = pushItem(parent, p) || peek(parent); 411 if(!equal(p.value, ':')){ p.msg = p.msg || 'Excepted :'; } 412 else{ p = pushItem(parent, p); } 413 return assignmentExpression(parent, p); 414 } 415 function _GetAndSet(functionName, p){ 416 p = pushItem(parent, p) || peek(parent); 417 if(equal(p.value, ':')){ 418 p = pushItem(parent, p); 419 return assignmentExpression(parent, p); 420 } 421 else if(propertyName.indexOf(p.type) == -1){ p.msg = p.msg || 'Invalid' + functionName + 'property name!'; } 422 else { p = pushItem(parent, p); } 423 p = p? p: peek(parent); 424 if(!equal(p.value, '(')){ p.msg = p.msg || 'Excepted ('; } 425 else{ p = pushItem(parent, p); } 426 p = p? p: peek(parent); 427 if(equal(functionName, 'set')){ 428 if(!equal(p.type, 'Identifier')){ p.msg = p.msg || 'Set property must one parameter!'; } 429 else{ p = pushItem(parent, p); } 430 } 431 p = p? p: peek(parent); 432 if(!equal(p.value, ')')){ p.msg = p.msg || 'Excepted )'; } 433 else{ p = pushItem(parent, p); } 434 p = p? p: peek(parent); 435 if(!equal(p.value, '{')){ p.msg = p.msg || 'Excepted {'; } 436 else{ p = pushItem(parent, p); } 437 p = (new Function()).functionBody(parent, p) || peek(parent); 438 if(!equal(p.value, '}')){ p.msg = p.msg || 'Excepted }'; } 439 else{ p = pushItem(parent, p); } 440 return p; 441 } 442 } 443 //function propertyName(parent, p) { } 444 function memberExpression(parent, p, isNewExpressionCall) { 445 p = primaryExpression(parent, p); 446 if(p){ 447 if(equal(p.value, 'function')){ p = (new Function()).functionExpression(parent, p); } 448 else if(equal(p.value, 'new')){ 449 p = pushItem(parent, p); 450 p = memberExpression(parent, p); 451 return argument(parent, p); 452 } 453 else{ 454 p.msg = p.msg || 'Excepted primary expression!'; 455 return p; 456 } 457 } 458 else{ p = peek(parent); } 459 return memberExtendExpression(parent, p); 460 } 461 function newExpression(parent, p) { 462 while(equal(p.value, 'new')){ 463 p = pushItem(parent, p) || peek(parent); 464 } 465 return memberExpression(parent, p); 466 } 467 function callExpression(parent, p) { 468 p = argument(parent, p); 469 return memberExtendExpression(parent, p); 470 } 471 function argument(parent, p, primaryCall) { 472 setFunctionType(parent); 473 var arg = {type: 'Argumments', child: []}; 474 parent.push(arg), parent = arg.child; 475 p = p? p: peek(parent); 476 if(equal(p.value, '(')){ p = pushItem(parent, p); } 477 else { p.msg = p.msg || 'Excepted ('; } 478 p = p? p: peek(parent); 479 if(!equal(p.value, ')')){ 480 p = argumentList(parent, p) || peek(parent); 481 if(equal(p.value, ')')){ p = pushItem(parent, p); } 482 else { 483 p.msg = p.msg || 'Excepted )'; 484 return p; 485 } 486 } 487 else{ p = pushItem(parent, p, primaryCall? 'Excepted expression!': ''); } 488 } 489 function memberExtendExpression(parent, p){ 490 p = p? p: peek(parent); 491 while(['(', '[', '.'].indexOf(p.value) > -1){ 492 if(equal(p.value, '(')){ p = argument(parent, p); } 493 else if(equal(p.value, '[')){ 494 pushItem(parent, p); 495 p = expression(parent) || peek(parent); 496 if(equal(p.value, ']')){ p = pushItem(parent, p); } 497 else{ p.msg = p.msg || 'Excepted ]'; } 498 } 499 else{ 500 p = pushItem(parent, p) || peek(parent); 501 if(equal(p.type, 'Identifier') || equal(p.type, 'Reservedword')){ p = pushItem(parent, p); } 502 else{ p.msg = p.msg || 'Excepted IdentifierName!'; } 503 } 504 p = p? p: peek(parent); 505 } 506 return p; 507 } 508 function setFunctionType(parent, part){ 509 var parts = ['Comment', 'WhiteSpace', 'Lineterminate']; 510 for(var index = parent.length - 1; index > -1 && parts.indexOf(parent[index].type) > -1; index--) ; 511 if(parent[index] && equal(parent[index].type, 'Identifier')){ parent[index].type = 'FunctionName'; } 512 } 513 function argumentList(parent, p) { 514 do{ 515 p = assignmentExpression(parent, p) || peek(parent); 516 if(!equal(p.value, ',')){ return p; } 517 p = pushItem(parent, p); 518 }while(true); 519 } 520 function leftHandSideExpression(parent, p) { 521 p = p? p: peek(parent); 522 if(equal(p.value, 'new')){ return newExpression(parent, p); } 523 p = memberExpression(parent, p) || peek(parent); 524 if(equal(p.value, '(')){ return callExpression(parent, p); } 525 return p; 526 } 527 function postfixExpression(parent, p) { 528 p = leftHandSideExpression(parent, p) || peek(parent); 529 if(['++', '--'].indexOf(p.value) == -1){ 530 var assignmentOperator = ['=', '*=', '/=', '%=', '+=', '-=', '<<=', '>>=', '>>>=', '&=', '^=', '|=']; 531 if(assignmentOperator.indexOf(p.value) > -1){ 532 p = pushItem(parent, p); 533 p = assignmentExpression(parent, p); 534 } 535 return p; 536 } 537 pushItem(parent, p, p.haveLineTerminator? 'No line terminator here!': ''); 538 } 539 function unaryExpression(parent, p) { 540 var unaryOp = ['++', '--', '+', '-', '!', '~', 'typeof', 'delete', 'void']; 541 p = p ? p : peek(parent); 542 if (unaryOp.indexOf(p.value) > -1) { 543 p = pushItem(parent, p); 544 return unaryExpression(parent); 545 } 546 else { return postfixExpression(parent, p); } 547 } 548 /*function multiplicativeExpression(parent, p){} 549 function additiveExpression(parent, p){} 550 function shiftExpression(parent, p){} 551 function relationalExpression(parent, p){} 552 function RelationalExpressionNoIn(parent, p){} 553 function equalityExpression(parent, p){} 554 function equalityExpressionNoIn(parent, p){} 555 function bitwiseANDExpression(parent, p){} 556 function bitwiseANDExpressionNoIn(parent, p){} 557 function bitwiseXORExpression(parent, p){} 558 function bitwiseXORExpressionNoIn(parent, p){} 559 function bitwiseORExpression(parent, p){} 560 function bitwiseORExpressionNoIn(parent, p){} 561 function logicalANDExpression(parent, p){} 562 function logicalANDExpressionNoIn(parent, p){} 563 function logicalORExpression(parent, p) {} 564 function logicalORExpressionNoIn(parent, p) {} 565 function logicalExpression(parent, p) {} 566 function logicalORExpressionNoIn(parent, p){}*/ 567 function operationExpression(parent, p, noIn) { 568 var logicalOp = ['||', '&&', '|', '^', '&', '==', '!=', '===', '!==', '<', '>', '<=', '>=', 'instanceof', '<<', '>>', '>>>', '+', '-', '*', '/', '%']; 569 if(!noIn){ logicalOp.push('in'); } 570 do{ 571 p = unaryExpression(parent, p) || peek(parent, p); 572 if(logicalOp.indexOf(p.value) == -1){ return p; } 573 p = pushItem(parent, p); 574 }while(true); 575 } 576 function conditionalExpression(parent, p, noIn) { 577 p = operationExpression(parent, p, noIn) || peek(parent, p); 578 if(!equal(p.value, '?')){ return p; } 579 p = pushItem(parent, p); 580 p = assignmentExpression(parent, p, noIn) || peek(parent, p); 581 if(equal(p.value, ':')){ p = pushItem(parent, p); } 582 else { p.msg = p.msg || 'Excepted :'; } 583 return assignmentExpression(parent, p, noIn); 584 } 585 //function conditionalExpressionNoIn(parent, p){} 586 function assignmentExpression(parent, p, noIn) { 587 return conditionalExpression(parent, p, noIn); 588 } 589 //function assignmentExpressionNoIn(parent, p){} 590 function expression(parent, p, noIn) { 591 var exp = { type: 'Expression', expressions: [] }; 592 parent.push(exp), parent = exp.expressions; 593 do{ 594 p = assignmentExpression(parent, p, noIn) || peek(parent); 595 if(equal(p.value, ',')){ p = pushItem(parent, p); } 596 else { return p; } 597 }while(true); 598 } 599 //function expressionNoIn(parent, p){} 600 } 601 function Statement(parent, p) { 602 var _Exp = new Expression(); 603 this.statement = statement; 604 this.isStatementStart = isStatementStart; 605 606 function statement(parent, p) { 607 p = p ? p : peek(parent); 608 switch (p.value) { 609 case '{': return block(parent, p); 610 case 'var': return variableStatement(parent, p); 611 case ';': return emptyStatement(parent, p); 612 case 'if': return ifStatement(parent, p); 613 case 'do': 614 case 'while': 615 case 'for': return iterationStatement(parent, p); 616 case 'continue': return continueStatement(parent, p); 617 case 'break': return breakStatement(parent, p); 618 case 'return': return returnStatement(parent, p); 619 case 'with': return withStatement(parent, p); 620 case 'switch': return switchStatement(parent, p); 621 case 'throw': return throwStatement(parent, p); 622 case 'try': return tryStatement(parent, p); 623 case 'debugger': return debuggerStatement(parent, p); 624 //case 'label': return labelStatement(parent, p); 625 case 'function': return pushItem(parent, p, 'Invalid statement start!'); 626 default: 627 if(equal(p.type, 'Identifier')){ 628 var currIndex = i, test; 629 try{ 630 test = peek([]); 631 }catch(e){ 632 test = {value: 'not :'} 633 } 634 i = currIndex; 635 if(equal(test.value, ':')){ return labelStatement(parent, p); } 636 } 637 if(!isExpressionStart(p)){ return p; } 638 return expressionStatement(parent, p); 639 } 640 } 641 function block(parent, p) { 642 var b = { type: 'BlockStatement', statement: [] }; 643 parent.push(b), parent = b.statement; 644 p = p ? p : peek(parent); 645 if(equal(p.value, '{')){ p = pushItem(parent, p); } 646 else { p.msg = p.msg || 'Excepted {'; } 647 p = p ? p : peek(parent); 648 if(equal(p.value, '}')){ return pushItem(parent, p); } 649 p = statementList(parent, p); 650 if(equal(p.value, '}')){ return pushItem(parent, p); } 651 else { p.msg = p.msg || 'Excepted }'; } 652 return p; 653 } 654 function statementList(parent, p) { 655 do{ 656 p = statement(parent, p); 657 if(p && !isStatementStart(p)){ return p; } 658 }while(true); 659 } 660 function variableStatement(parent, p) { 661 var varDeclar = { type: 'VariableDeclaration', declarList: [] }; 662 p = p ? p : peek(parent); 663 parent.push(varDeclar), parent = varDeclar.declarList; 664 p = pushItem(parent, p) || peek(parent); 665 p = variableDeclarationList(parent, p) || peek(parent); 666 if(!equal(p.value, ';')){ 667 if(!p.haveLineTerminator && !equal(p.value, '}')){ p.msg = p.msg || 'Excepted ;'; } 668 } 669 else{ p = pushItem(parent, p); } 670 return p; 671 } 672 function variableDeclarationList(parent, p, noIn) { 673 p = p ? p : peek(parent); 674 do { 675 p = variableDeclaration(parent, p, noIn) || peek(parent); 676 if(!equal(p.value, ',')){ 677 if(equal(p.value, ';') || p.haveLineTerminator){ return p; } 678 else if(!equal(p.type, 'Identifier')){ p = pushItem(parent, p, 'Excepted ,'); } 679 else { p.msg = p.msg || 'Excepted ,'; } 680 } 681 else { p = pushItem(parent, p); } 682 } while (true); 683 } 684 function variableDeclaration(parent, p, noIn) { 685 p = p ? p : peek(parent); 686 if (!equal(p.type, 'Identifier')) { 687 if(!p.msg){ 688 if(equal(p.type, 'Reservedword')){ p.msg = 'Identifier can not be reservedword!'; } 689 else{ p.msg = 'Excepted identifier!' } 690 } 691 } 692 else { p = pushItem(parent, p); } 693 p = p ? p : peek(parent); 694 if(!equal(p.value, '=')){ return p; } 695 p = pushItem(parent, p); 696 return _Exp.assignmentExpression(parent, p, noIn); 697 } 698 function emptyStatement(parent, p) { 699 var emptyState = { type: p.type, value: p.value }; 700 parent.push(emptyState); 701 } 702 function expressionStatement(parent, p) { 703 p = _Exp.expression(parent, p) || peek(parent); 704 if(equal(p.value, ';')){ return pushItem(parent, p); } 705 else if(!equal(p.value, '}') && !p.haveLineTerminator) { p.msg = p.msg || 'Excepted ;'; } 706 return p; 707 } 708 function ifStatement(parent, p) { 709 var ifState = { type: 'IfStatement', statement: [] }; 710 parent.push(ifState), parent = ifState.statement; 711 p = pushItem(parent, p) || peek(parent); 712 if(equal(p.value, '(')){ p = pushItem(parent, p); } 713 else{ p.msg = p.msg || 'Excepted ('; } 714 p = _Exp.expression(parent, p) || peek(parent); 715 if(equal(p.value, ')')){ p = pushItem(parent, p); } 716 else { p.msg = p.msg || 'Excepted )'; } 717 p = statement(parent, p) || peek(parent); 718 if(!equal(p.value, 'else')){ return p; } 719 p = pushItem(parent, p); 720 return statement(parent); 721 } 722 function iterationStatement(parent, p) { 723 var loop = { type: 'IterationStatement', statement: [] }; 724 parent.push(loop), parent = loop.statement; 725 pushItem(parent, p); 726 p = p? p: peek(parent); 727 if (equal(p.value, 'do')) { return doStatement(parent); } 728 else if (equal(p.value, 'while')) { return whileStatement(parent); } 729 else if (equal(p.value, 'for')) { return forStatement(parent); } 730 else { p.msg = p.msg || 'Excepted do or while or for!'; } 731 return p; 732 733 function doStatement(parent, p) { 734 p = statement(parent, p) || peek(parent); 735 if(!equal(p.value, 'while')){ p.msg = p.msg || 'Excepted While!'; } 736 else { p = pushItem(parent, p); } 737 return whileStatement(parent, p); 738 } 739 function whileStatement(parent, p) { 740 p = p? p: peek(parent); 741 if(!equal(p.value, '(')){ p.msg = p.msg || 'Excepted ('; } 742 else{ p = pushItem(parent, p); } 743 p = _Exp.expression(parent, p) || peek(parent); 744 if(!equal(p.value, ')')){ p.msg = p.msg || 'Excepted )'; } 745 else{ p = pushItem(parent, p); } 746 return statement(parent, p); 747 } 748 function forStatement(parent, p) { 749 p = p? p: peek(parent); 750 if(!equal(p.value, '(')){ p.msg = p.msg || 'Excepted ('; } 751 else{ p = pushItem(parent, p); } 752 p = p? p: peek(parent); 753 if(equal(p.value, 'var')){ 754 p = pushItem(parent, p); 755 p = variableDeclaration(parent, p, true) || peek(parent); 756 if(equal(p.value, ',') || equal(p.value, ';')){ 757 while(equal(p.value, ',')){ 758 p = pushItem(parent, p); 759 p = variableDeclaration(parent, p, true) || peek(parent); 760 } 761 } 762 } 763 else if(!equal(p.value, ';')){ 764 var currIndex = i, test; 765 try{ 766 test = _Exp.leftHandSideExpression([], p) || peek([]); 767 }catch(e){ 768 test = { value: 'not in' }; 769 } 770 i = currIndex; 771 if(equal(test.value, 'in')){ p = _Exp.leftHandSideExpression(parent, p) || peek(parent); } 772 else { p = _Exp.expression(parent, p, true) || peek(parent); } 773 } 774 if(equal(p.value, 'in')){ 775 pushItem(parent, p); 776 p = _Exp.expression(parent); 777 } 778 else if(equal(p.value, ';')){ 779 p = pushItem(parent, p) || peek(parent); 780 if(!equal(p.value, ';')){ 781 p = _Exp.expression(parent, p) || peek(parent); 782 if(equal(p.value, ';')){ p = pushItem(parent, p); } 783 else { p.msg = p.msg || 'Excepted ;'; } 784 } 785 else { p = pushItem(parent, p); } 786 p = p? p: peek(parent); 787 if(!equal(p.value, ')')){ p = _Exp.expression(parent, p); } 788 } 789 else{ p.msg = p.msg || 'Excepted ;'; } 790 p = p? p: peek(parent); 791 if(equal(p.value, ')')){ p = pushItem(parent, p); } 792 else { p.msg = p.msg || 'Excepted )'; } 793 return statement(parent, p); 794 } 795 } 796 function continueStatement(parent, p) { 797 var con = { type: 'ContinueStatement', statement: [] }; 798 parent.push(con), parent = con.statement; 799 p = pushItem(parent, p) || peek(parent); 800 if(p.haveLineTerminator){ return p; } 801 else if(equal(p.type, 'Identifier')){ p = pushItem(parent, p); } 802 p = p? p: peek(parent); 803 if(p.haveLineTerminator){ return p; } 804 else if(equal(p.value, ';')){ p = pushItem(parent, p); } 805 else if(!equal(p.value, '}')) { p.msg = p.msg || 'Excepted ;'; } 806 return p; 807 } 808 function breakStatement(parent, p) { 809 var b = { type: 'BreakStatement', statement: [] }; 810 parent.push(b), parent = b.statement; 811 p = pushItem(parent, p) || peek(parent); 812 if(p.haveLineTerminator){ return p; } 813 else if(equal(p.type, 'Identifier')){ p = pushItem(parent, p); } 814 p = p? p: peek(parent); 815 if(p.haveLineTerminator){ return p; } 816 else if(equal(p.value, ';')){ p = pushItem(parent, p); } 817 else if(!equal(p.value, '}')) { p.msg = p.msg || 'Excepted ;'; } 818 return p; 819 } 820 function returnStatement(parent, p) { 821 var r = { type: 'ReturnStatement', statement: [] }; 822 parent.push(r), parent = r.statement; 823 p = pushItem(parent, p) || peek(parent); 824 if(p.haveLineTerminator){ return p; } 825 else if(equal(p.value, ';')){ p = pushItem(parent, p); } 826 else if(!equal(p.value, '}')){ 827 p = _Exp.expression(parent, p) || peek(parent); 828 if(p.haveLineTerminator){ return p; } 829 else if(equal(p.value, ';')){ p = pushItem(parent, p); } 830 else if(!equal(p.value, '}')){ p.msg = p.msg || 'Excepted ;'; } 831 } 832 return p; 833 } 834 function withStatement(parent, p) { 835 var w = { type: 'WhithStatement', statement: [] }; 836 parent.push(w), parent = w.statement; 837 p = pushItem(parent, p) || peek(parent); 838 if(equal(p.value, '(')){ p = pushItem(parent, p); } 839 else{ p.msg = p.msg || 'Excepted ('; } 840 p = _Exp.expression(parent, p) || peek(parent); 841 if(equal(p.value, ')')){ p = pushItem(parent, p); } 842 else{ p.msg = p.msg || 'Excepted )'; } 843 return statement(parent, p); 844 } 845 function switchStatement(parent, p) { 846 var s = { type: 'SwitchStatement', statement: [] }; 847 parent.push(s), parent = s.statement; 848 p = pushItem(parent, p) || peek(parent); 849 if(equal(p.value, '(')){ p = pushItem(parent, p); } 850 else{ p.msg = p.msg || 'Excepted ('; } 851 p = _Exp.expression(parent, p) || peek(parent); 852 if(equal(p.value, ')')){ p = pushItem(parent, p); } 853 else{ p.msg = p.msg || 'Excepted )'; } 854 return caseBlock(parent, p); 855 } 856 function caseBlock(parent, p) { 857 var c = { type: 'CaseStatement', statement: [] }; 858 globalVariable.currInstance = 'caseBlock'; 859 parent.push(c), parent = c.statement; 860 p = p? p: peek(parent); 861 if(equal(p.value, '{')){ p = pushItem(parent, p); } 862 else{ p.msg = p.msg || 'Excepted {'; } 863 p = p? p: peek(parent); 864 if(equal(p.value, '}')){ return pushItem(parent, p); } 865 var haveDefault = false; 866 do{ 867 p = p? p: peek(parent); 868 if(equal(p.value, 'case')){ 869 pushItem(parent, p); 870 p = _Exp.expression(parent); 871 } 872 else if(equal(p.value, 'default')){ 873 if(haveDefault){ p.msg = p.msg || 'Repeat default keyword!'; } 874 p = pushItem(parent, p); 875 haveDefault = true; 876 } 877 else if(equal(p.value, '}')){ return pushItem(parent, p); } 878 p = p? p: peek(parent); 879 if(equal(p.value, ':')){ p = pushItem(parent, p); } 880 else { p.msg = p.msg || 'Excepted :'; } 881 p = statementList(parent, p); 882 }while(true); 883 } 884 function labelStatement(parent, p) { 885 var l = { type: 'LablelStatement', statement: [] }; 886 parent.push(l), parent = l.statement; 887 p = pushItem(parent, p) || peek(parent); 888 if(equal(p.value, ':')){ p = pushItem(parent, p); } 889 else { p.msg = p.msg || 'Excepted :'; } 890 return statement(parent, p); 891 } 892 function throwStatement(parent, p) { 893 var t = { type: 'ThrowStatement', statement: [] }; 894 parent.push(t), parent = t.statement; 895 p = pushItem(parent, p) || peek(parent); 896 if(p.haveLineTerminator){ p.msg = p.msg || 'No lineTerminator here!'; return p; } 897 p = _Exp.expression(parent, p) || peek(parent); 898 if(p.haveLineTerminator){ return p; } 899 else if(equal(p.value, ';')){ return pushItem(parent, p); } 900 else if(!equal(p.value, '}')){ p.msg = p.msg || 'Excepted ;'; } 901 return p; 902 } 903 function tryStatement(parent, p) { 904 var t = { type: 'TryStatement', statement: [] }, haveCatch = false; 905 parent.push(t), parent = t.statement; 906 pushItem(parent, p); 907 p = block(parent) || peek(parent); 908 if(equal(p.value, 'catch')){ 909 haveCatch = true; 910 p = pushItem(parent, p); 911 p = catchStatement(parent, p); 912 } 913 p = p? p: peek(parent); 914 if(equal(p.value, 'finally')){ 915 p = pushItem(parent, p); 916 p = block(parent, p); 917 } 918 else if(!haveCatch) { p.msg = p.msg || 'Excepted catch or finally!'; } 919 return p; 920 } 921 function catchStatement(parent, p) { 922 var c = { type: 'CatchStatement', statement: [] }; 923 parent.push(c), parent = c.statement; 924 p = pushItem(parent, p) || peek(parent); 925 if(equal(p.value, '(')){ p = pushItem(parent, p); } 926 else{ p.msg = p.msg || 'Excepted ('; } 927 p = p? p: peek(parent); 928 if(equal(p.type, 'Identifier')){ p = pushItem(parent, p); } 929 else { p.msg = p.msg || 'Excepted identifier!'; } 930 p = p? p: peek(parent); 931 if(equal(p.value, ')')){ p = pushItem(parent, p); } 932 else{ p.msg = p.msg || 'Excepted )'; } 933 return block(parent, p); 934 } 935 function debuggerStatement(parent, p) { 936 var d = { type: 'DebuggerStatement', statement: [] }; 937 parent.push(d), parent = d.statement; 938 p = pushItem(parent, p) || peek(parent); 939 if(p.haveLineTerminator){ return p; } 940 else if(equal(p.value, ';')){ return pushItem(parent, p); } 941 else if(!equal(p.value, '}')){ p.msg = p.msg || 'Excepted ;'; } 942 return p; 943 } 944 function isExpressionStart(p){ 945 var valueArray = ['this', 'null', 'true', 'false', '{', '[', '(', 'new', '++', '--', '+', '-', '!', '~', 'typeof', 'delete', 'void', '/'], 946 typeArray = ['Identifier', 'StringLiteral', 'StringLiteral', 'RegularExpressionLiteral']; 947 return typeArray.indexOf(p.type) > -1 || valueArray.indexOf(p.value) > -1; 948 } 949 function isStatementStart(p){ 950 var keyValue = ['var', 'return', ';', 'if', 'for', 'do', 'while', 'switch', 'with', 'debugger', 'continue', 'break', 'throw', 'try']; 951 return isExpressionStart(p) || keyValue.indexOf(p.value) > -1; 952 } 953 } 954 function Function(parent, p) { 955 this.functionExpression = functionExpression; 956 this.program = program; 957 this.functionBody = functionBody; 958 959 function functionDeclaration(parent, p) { 960 var f = { type: 'FunctionDeclaration', declaration: [] }; 961 parent.push(f), parent = f.declaration; 962 p = pushItem(parent, p) || peek(parent); 963 if(equal(p.type, 'Identifier')){ 964 p.type = 'FunctionName'; 965 p = pushItem(parent, p); 966 } 967 else{ p.msg = p.msg || 'Excepted function name!' } 968 p = p? p: peek(parent); 969 if(equal(p.value, '(')){ p = pushItem(parent, p); } 970 else{ p.msg = p.msg || 'Excepted (' } 971 p = p? p: peek(parent); 972 if(!equal(p.value, ')')){ p = formalParameterList(parent, p) || peek(parent); } 973 p = p? p: peek(parent); 974 if(equal(p.value, ')')){ p = pushItem(parent, p); } 975 else{ p.msg = p.msg || 'Excepted )' } 976 p = p? p: peek(parent); 977 if(equal(p.value, '{')){ p = pushItem(parent, p); } 978 else{ p.msg = p.msg || 'Excepted {' } 979 p = functionBody(parent, p) || peek(parent); 980 if(equal(p.value, '}')){ p = pushItem(parent, p); } 981 else{ p.msg = p.msg || 'Excepted }' } 982 return p; 983 } 984 function functionExpression(parent, p) { 985 var f = { type: 'FunctionDeclaration', declaration: [] }; 986 parent.push(f), parent = f.declaration; 987 p = pushItem(parent, p) || peek(parent); 988 if(equal(p.type, 'Identifier')){ 989 p.type = 'FunctionName'; 990 p = pushItem(parent, p); 991 } 992 p = p? p: peek(parent); 993 if(equal(p.value, '(')){ p = pushItem(parent, p); } 994 else{ p.msg = p.msg || 'Excepted (' } 995 p = p? p: peek(parent); 996 if(!equal(p.value, ')')){ p = formalParameterList(parent, p) || peek(parent); } 997 p = p? p: peek(parent); 998 if(equal(p.value, ')')){ p = pushItem(parent, p); } 999 else{ p.msg = p.msg || 'Excepted )' } 1000 p = p? p: peek(parent); 1001 if(equal(p.value, '{')){ p = pushItem(parent, p); } 1002 else{ p.msg = p.msg || 'Excepted {' } 1003 p = functionBody(parent, p) || peek(parent); 1004 if(equal(p.value, '}')){ p = pushItem(parent, p); } 1005 else{ p.msg = p.msg || 'Excepted }' } 1006 return p; 1007 } 1008 function formalParameterList(parent, p) { 1009 do{ 1010 p = p? p: peek(parent); 1011 if(equal(p.type, 'Identifier')){ p = pushItem(parent, p); } 1012 else { p.msg = p.msg || 'Function parameter muste be identifier!'; } 1013 p = p? p: peek(parent); 1014 if(equal(p.value, ',')){ p = pushItem(parent, p); } 1015 else if(equal(p.value, ')')){ return p; } 1016 else { p = pushItem(parent, p, 'Excpted ,'); } 1017 }while(true); 1018 } 1019 function functionBody(parent, p) { 1020 p = p? p: peek(parent); 1021 if(equal(p.value, '}')){ return p; } 1022 var f = { type: 'FunctionBody', body: [] }, strictModel = globalVariable.strictModel; 1023 parent.push(f), parent = f.body; 1024 p = p? p: peek(parent); 1025 if(equal(p.value, '"use strict"') || equal(p.value, "'use strict'")){ globalVariable.strictModel = true; } 1026 p = sourceElements(parent, p); 1027 globalVariable.strictModel = strictModel; 1028 return p; 1029 } 1030 function program(parent){ 1031 var p = peek(parent); 1032 if(equal(p.value, '"use strict"') || equal(p.value, "'use strict'")){ globalVariable.strictModel = true; } 1033 do{ 1034 p = sourceElements(parent, p); 1035 if(p){ p = pushItem(parent, p, 'Syntax error!'); } 1036 }while(true); 1037 } 1038 function sourceElements(parent, p) { 1039 do{ 1040 p = sourceElement(parent, p); 1041 if(p && !isSourceElementStart(p)){ return p; } 1042 }while(true); 1043 } 1044 function sourceElement(parent, p) { 1045 p = p ? p : peek(parent); 1046 if(equal(p.value, 'function')){ return functionDeclaration(parent, p); } 1047 else { return (new Statement()).statement(parent, p); } 1048 } 1049 function isSourceElementStart(p){ 1050 if(equal(p.value, 'function')){ return true; } 1051 else{ 1052 var state = new Statement(); 1053 return state.isStatementStart(p); 1054 } 1055 } 1056 } 1057 function eol(pos) { 1058 i = pos ? pos : i; 1059 return i >= string.length; 1060 } 1061 function isHex(ch) { 1062 return /[0-9a-fA-F]/g.test(ch); 1063 } 1064 function isSpace(ch) { 1065 return ['\u0009', '\u000B', '\u0009C', '\u0020', '\u00A0', '\uFEFF'].indexOf(ch) > -1; 1066 } 1067 function isLineTerminator(ch) { 1068 return ['\u000A', '\u000D', '\u2028', '\u2029'].indexOf(ch) > -1; 1069 } 1070 function isWhiteSpace(ch){ 1071 return isSpace(ch) || isLineTerminator(ch); 1072 } 1073 function isItemInArray(array, item) { 1074 return array.indexOf(item) > -1; 1075 } 1076 function isDigit(ch) { 1077 return /\d/g.test(ch); 1078 } 1079 function isReservedWord(word) { 1080 if (!word) { return false; } 1081 var keyWord = ["break", "do", "instanceof", "pof", "case", "else", "new", "var", "catch", "finally", "return", "void", 'continue', "for", 1082 "switch", "while", "debugger", "function", 'this', 'with', 'default', "if", "throw", "delete", "in", "try"], 1083 nullReserved = ['null'], 1084 booleanReserved = ['true', 'false'], 1085 futureReserved = ["class", "enum", "extends", "super", "export", "import"], 1086 strictReserved = ["implements", 'let', "private", "public", "interface", "package", "protected", "static", 'yield'], 1087 reserved = keyWord.concat(nullReserved).concat(futureReserved).concat(booleanReserved), 1088 strictModel = globalVariable.strictModel; 1089 if (strictModel) { reserved = reserved.concat(strictReserved); } 1090 return reserved.indexOf(word) > -1; 1091 } 1092 function equal(e1, e2, deep) { 1093 return deep ? e1 === e2 : e1 == e2; 1094 } 1095 function pushItem(parent, p, msg) { 1096 if (!p || !p.value) { return; } 1097 var o = { type: p.type, value: p.value }; 1098 if (p.msg || msg) { 1099 o.type = 'Exception'; 1100 o.msg = p.msg || msg; 1101 } 1102 parent.push(o); 1103 } 1104 } 1105 </script> 1106 </body> 1107 </html>

浙公网安备 33010602011771号