1/* 2 * Copyright (c) 2022-2023 Shenzhen Kaihong Digital Industry Development Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16const { NapiLog } = require('./NapiLog'); 17const re = require('./re'); 18 19const MAX_DECIMAL = 10; 20const MAX_BINARY = 2; 21const MAX_OCTAL = 8; 22const MAX_HEXADECIMAL = 16; 23const STAT_SIZE = 100; 24 25const DataType = { 26 INT8: 1, 27 INT16: 2, 28 INT32: 3, 29 INT64: 4, 30 STRING: 5, 31 NODE: 6, 32 ATTR: 7, 33 ARRAY: 8, 34 REFERENCE: 9, 35 DELETE: 10, 36 BOOL: 11, 37}; 38const NodeType = { 39 DATA: 0, 40 COPY: 1, 41 REFERENCE: 2, 42 DELETE: 3, 43 TEMPLETE: 4, 44 INHERIT: 5, 45}; 46 47class NodeTools {} 48 49function getRoot(node) { 50 while (node.parent_ !== undefined) { 51 node = node.parent_; 52 } 53 return node; 54} 55 56NodeTools.isElders = function (node, elders) { 57 while (node !== undefined) { 58 if (node === elders) { 59 return true; 60 } 61 node = node.parent_; 62 } 63 return false; 64}; 65 66NodeTools.getPathByNode = function (node, expandRef = true) { 67 if (node === null) { 68 return ''; 69 } 70 let ret = node.name_; 71 while (node !== null && node.parent_ !== undefined) { 72 node = node.parent_; 73 if (expandRef && node.nodeType_ === NodeType.REFERENCE) { 74 if (node.ref_.startsWith(getRoot(node).name_)) { 75 node = NodeTools.getNodeByPath(getRoot(node), node.ref_); 76 } else { 77 node = NodeTools.getNodeByPath(node.parent_, node.ref_); 78 } 79 } 80 if (node !== null) { 81 ret = node.name_ + '.' + ret; 82 } 83 } 84 return ret; 85}; 86NodeTools.getNodeByPath = function (node, path) { 87 let ps = path.split('.'); 88 if (ps[0] === 'root') { 89 ps.shift(); 90 } 91 for (let p in ps) { 92 node = NodeTools.findChildByName(node, ps[p]); 93 if (node === null) { 94 return null; 95 } 96 } 97 return node; 98}; 99 100NodeTools.lookupInherit = function (node) { 101 if ( 102 node.type_ === DataType.NODE && 103 node.nodeType_ === NodeType.INHERIT && 104 node.parent_.nodeType_ === NodeType.INHERIT 105 ) { 106 let p = NodeTools.lookupInherit(node.parent_); 107 if (p === null) { 108 return p; 109 } 110 return NodeTools.findChildByName(p, node.ref_); 111 } 112 return NodeTools.findChildByName(node.parent_, node.ref_); 113}; 114 115NodeTools.lookup = function (node) { 116 let refname; 117 if ( 118 node.type_ === DataType.NODE && 119 (node.nodeType_ === NodeType.COPY || 120 node.nodeType_ === NodeType.REFERENCE || 121 node.nodeType_ === NodeType.INHERIT) 122 ) { 123 refname = node.ref_; 124 } 125 else if ( 126 node.type_ === DataType.ATTR && 127 node.value_.type_ === DataType.REFERENCE 128 ) { 129 refname = node.value_.value_; 130 } 131 else { return null; } 132 if (refname.indexOf('.') >= 0) { 133 return NodeTools.getNodeByPath(getRoot(node), refname); 134 } 135 136 let ret = NodeTools.findChildByName(node.parent_, refname); 137 if (ret === null) { 138 if ( 139 node.type_ === DataType.NODE && 140 node.nodeType_ === NodeType.INHERIT && 141 node.parent_.nodeType_ === NodeType.INHERIT 142 ) { 143 ret = NodeTools.lookupInherit(node); 144 } 145 } 146 return ret; 147}; 148 149NodeTools.recursionNode = function (node, callback) { 150 if (node.type_ === DataType.NODE) { 151 callback(node); 152 for (let n in node.value_) { 153 NodeTools.recursionNode(node.value_[n], callback); 154 } 155 } 156}; 157NodeTools.recursionAll = function (node, callback, isForward) { 158 let ret = false; 159 if (isForward) { 160 ret = callback(node); 161 } 162 if (node.type_ === DataType.NODE) { 163 for (let i = 0; i < node.value_.length; i++) { 164 if (NodeTools.recursionAll(node.value_[i], callback, isForward)) { 165 i--; 166 } 167 } 168 } 169 if (!isForward) { 170 ret = callback(node); 171 } 172 return ret; 173}; 174NodeTools.redefineCheck = function (node) { 175 let ret = true; 176 NodeTools.recursionNode(node, (pn) => { 177 let nameMap = []; 178 for (let i in pn.value_) { 179 if (nameMap.indexOf(pn.value_[i].name_) >= 0) { 180 pn.value_[i].errMsg_ = '重名:' + pn.value_[i].lineno_; 181 ret = false; 182 } else { 183 nameMap.push(pn.value_[i].name_); 184 pn.value_[i].errMsg_ = null; 185 } 186 } 187 }); 188 return ret; 189}; 190function separate(node) { 191 let pn = node.parent_; 192 if (pn === null) { 193 return; 194 } 195 for (let i in pn.value_) { 196 if (pn.value_[i] === node) { 197 pn.value_.splice(i, 1); 198 } 199 } 200} 201NodeTools.findChildByName = function (node, name) { 202 for (let i in node.value_) { 203 if (node.value_[i].name_ === name) { 204 return node.value_[i]; 205 } 206 } 207 return null; 208}; 209 210NodeTools.copyNode = function (node, parent) { 211 let ret = { 212 type_: node.type_, 213 name_: node.name_, 214 lineno_: node.lineno_, 215 parent_: parent, 216 }; 217 if (node.raw_ !== undefined) { 218 ret.raw_ = node.raw_; 219 } 220 switch (node.type_) { 221 case DataType.INT8: 222 case DataType.INT16: 223 case DataType.INT32: 224 case DataType.INT64: 225 ret.value_ = node.value_; 226 ret.jinzhi_ = node.jinzhi_; 227 break; 228 case DataType.STRING: 229 ret.value_ = node.value_; 230 break; 231 case DataType.NODE: 232 ret.nodeType_ = node.nodeType_; 233 if ([NodeType.INHERIT, NodeType.COPY, NodeType.REFERENCE].indexOf(node.nodeType_) > -1) { 234 ret.ref_ = node.ref_; 235 } else if (!([NodeType.DATA, NodeType.TEMPLETE, NodeType.DELETE].indexOf(node.nodeType_) > -1)) { 236 NapiLog.logError('unknow node type:' + ret.lineno_); 237 } 238 ret.value_ = []; 239 for (let i in node.value_) { ret.value_.push(NodeTools.copyNode(node.value_[i], ret)); } 240 break; 241 case DataType.ATTR: 242 ret.value_ = NodeTools.copyNode(node.value_, ret); 243 break; 244 case DataType.ARRAY: 245 ret.value_ = []; 246 for (let i in node.value_) { ret.value_.push(NodeTools.copyNode(node.value_[i], ret)); } 247 break; 248 case DataType.REFERENCE: 249 ret.value_ = node.value_; 250 break; 251 case DataType.DELETE: 252 ret.value_ = null; 253 break; 254 case DataType.BOOL: 255 ret.value_ = node.value_; 256 break; 257 default: 258 NapiLog.logInfo('unknow', node.type_); 259 break; 260 } 261 return ret; 262}; 263 264function makeError(node, errStr) { 265 if (node.raw_ !== undefined) { 266 node.raw_.errMsg_ = errStr; 267 } 268} 269NodeTools.nodeNestCheck = function (node) { 270 NodeTools.recursionAll( 271 node, 272 (pn) => { 273 if (pn.type_ === DataType.NODE) { 274 if (pn.nodeType_ === NodeType.COPY && pn.raw_.errMsg_ === null) { 275 pn.raw_.errMsg_ = '有Copy的嵌套' + pn.raw_.lineno_; 276 } 277 } 278 return false; 279 }, 280 false 281 ); 282}; 283NodeTools.recursionCopyAndReferenceNodes = function (pn) { 284 let ref = NodeTools.lookup(pn); 285 if (ref === null) { 286 NapiLog.logError( 287 'reference not exist' + NodeTools.getPathByNode(pn) + ':' + pn.ref_ 288 ); 289 if (pn.nodeType_ === NodeType.COPY) { 290 makeError(pn, pn.name_ + ' 复制目标没找到!'); 291 } else { 292 makeError(pn, pn.name_ + ' 引用目标没找到!'); 293 } 294 return false; 295 } else if (ref.nodeType_ === NodeType.TEMPLETE) { 296 if (pn.nodeType_ === NodeType.COPY) { 297 makeError(pn, pn.name_ + ' 复制目标不能为模板节点!'); 298 } else { 299 makeError(pn, pn.name_ + ' 引用目标不能为模板节点!'); 300 } 301 return false; 302 } else if (ref.nodeType_ === NodeType.DELETE) { 303 if (pn.nodeType_ === NodeType.COPY) { 304 makeError(pn, pn.name_ + ' 复制目标不能为删除节点!'); 305 } else { 306 makeError(pn, pn.name_ + ' 引用目标不能为删除节点!'); 307 } 308 return false; 309 } else if (NodeTools.isElders(pn, ref)) { 310 NapiLog.logError( 311 'circular reference' + NodeTools.getPathByNode(pn) + ':' + pn.ref_ 312 ); 313 if (pn.nodeType_ === NodeType.COPY) { 314 makeError(pn, pn.name_ + ' 循环复制!'); 315 } else { 316 makeError(pn, pn.name_ + ' 循环引用!'); 317 } 318 return false; 319 } else if (pn.nodeType_ === NodeType.COPY) { 320 if (ref.nodeType_ === NodeType.COPY) { 321 pn.raw_.errMsg_ = '有Copy的嵌套:' + pn.raw_.lineno_; 322 } 323 pn.nodeType_ = NodeType.DATA; 324 let tref = NodeTools.copyNode(ref, pn.parent_); 325 tref.name_ = pn.name_; 326 NodeTools.merge(tref, pn); 327 pn.value_ = tref.value_; 328 return false; 329 } else if (pn.nodeType_ === NodeType.REFERENCE) { 330 pn.nodeType_ = ref.nodeType_; 331 pn.name_ = ref.name_; 332 pn.ref_ = ref.ref_; 333 NodeTools.merge(ref, pn); 334 separate(pn); 335 return true; 336 } 337 return false; 338}; 339 340NodeTools.checkInheritNode = function (pn) { 341 let ref = NodeTools.lookup(pn); 342 if (ref === null) { 343 makeError(pn, pn.name_ + ' 继承目标找不到!'); 344 } else if (ref.type_ !== DataType.NODE) { 345 makeError(pn, pn.name_ + ' 不能继承属性!'); 346 } else if (ref.nodeType_ === NodeType.REFERENCE) { 347 makeError(pn, pn.name_ + ' 不能继承引用类节点!'); 348 } else if (ref.nodeType_ === NodeType.DELETE) { 349 makeError(pn, pn.name_ + ' 不能继承删除类节点!'); 350 } else if (ref.nodeType_ === NodeType.DATA) { 351 makeError(pn, pn.name_ + ' 不能继承数据类节点!'); 352 } else if (ref.nodeType_ === NodeType.INHERIT) { 353 makeError(pn, pn.name_ + ' 不能继承继承类节点!'); 354 } else if (ref.nodeType_ === NodeType.COPY) { 355 makeError(pn, pn.name_ + ' 不能继承复制类节点!'); 356 } 357}; 358 359NodeTools.nodeExpand = function (node) { 360 NodeTools.recursionAll(node, (pn) => { 361 if (pn.type_ === DataType.NODE) { 362 if (pn.nodeType_ === NodeType.DELETE) { 363 separate(pn); 364 return true; 365 } 366 if (pn.nodeType_ === NodeType.COPY || pn.nodeType_ === NodeType.REFERENCE) { 367 return NodeTools.recursionCopyAndReferenceNodes(pn); 368 } 369 if (pn.nodeType_ === NodeType.INHERIT) { 370 NodeTools.checkInheritNode(pn); 371 } 372 } else if (pn.type_ === DataType.ATTR) { 373 if (pn.value_.type_ === DataType.DELETE) { 374 separate(pn); 375 return true; 376 } 377 if (pn.value_.type_ === DataType.REFERENCE) { 378 let ref = NodeTools.lookup(pn); 379 if (ref === null || ref.type_ !== DataType.NODE || ref.nodeType_ === NodeType.REFERENCE || 380 ref.nodeType_ === NodeType.TEMPLETE || ref.nodeType_ === NodeType.DELETE 381 ) { 382 NapiLog.logError('reference invalid node' + NodeTools.getPathByNode(pn) + ':' + pn.value_.value_); 383 if (ref === null) { 384 makeError(pn, pn.name_ + ' 找不到引用目标!'); 385 } else if (ref.type_ !== DataType.NODE) { 386 makeError(pn, pn.name_ + ' 不能引用属性!'); 387 } else if (ref.nodeType_ === NodeType.REFERENCE) { 388 makeError(pn, pn.name_ + ' 不能引用引用类节点!'); 389 } else if (ref.nodeType_ === NodeType.TEMPLETE) { 390 makeError(pn, pn.name_ + ' 不能引用模板类节点!'); 391 } else if (ref.nodeType_ === NodeType.DELETE) { 392 makeError(pn, pn.name_ + ' 不能引用删除类节点!'); 393 } 394 } else { 395 pn.refNode_ = ref; 396 } 397 } 398 } 399 return false; 400 }, false); 401}; 402 403NodeTools.inheritExpand = function (node) { 404 NodeTools.recursionAll( 405 node, 406 (pn) => { 407 let tt = re.match('^[a-zA-Z_]{1}[a-zA-Z_0-9]*$', pn.name_); 408 if (tt === null) { 409 makeError(pn, pn.name_ + ' 名字不合规范!'); 410 } 411 if (pn.type_ !== DataType.NODE) { 412 return false; 413 } 414 if (pn.nodeType_ !== NodeType.INHERIT) { 415 return false; 416 } 417 let inherit = NodeTools.lookup(pn); 418 if (inherit === null) { 419 NapiLog.logError( 420 'inherit invalid node: ' + NodeTools.getPathByNode(pn) + ':' + pn.ref_ 421 ); 422 makeError(pn, '继承目标找不到!'); 423 return false; 424 } 425 pn.nodeType_ = NodeType.DATA; 426 let tinherit = NodeTools.copyNode(inherit, pn.parent_); 427 NodeTools.merge(tinherit, pn); 428 pn.value_ = tinherit.value_; 429 return false; 430 }, 431 true 432 ); 433}; 434NodeTools.merge = function (node1, node2) { 435 if (node2 === null) { 436 return true; 437 } 438 if (node2.raw_ === undefined) { 439 node1.raw_ = node2; 440 } else { 441 node1.raw_ = node2.raw_; 442 } 443 if (node1.type_ === DataType.NODE) { 444 if (node1.name_ !== node2.name_) { 445 return false; 446 } 447 node1.nodeType_ = node2.nodeType_; 448 if (node2.nodeType_ === NodeType.INHERIT || node2.nodeType_ === NodeType.REFERENCE || node2.nodeType_ === NodeType.COPY) { 449 node1.ref_ = node2.ref_; 450 } 451 if (node1.value_ === undefined) { 452 node1.value_ = []; 453 } 454 455 for (let i in node2.value_) { 456 let child2 = node2.value_[i]; 457 let child1 = NodeTools.findChildByName(node1, child2.name_); 458 if (child1 === null) { 459 child1 = { 460 type_: child2.type_, 461 name_: child2.name_, 462 lineno_: child2.lineno_, 463 parent_: node1, 464 }; 465 node1.value_.push(child1); 466 } else if (child1.type_ !== child2.type_) { 467 child2.raw_.errMsg_ = 468 '所修改的子节的类型和父节点类型不同:' + child2.raw_.lineno_; 469 return false; 470 } 471 NodeTools.merge(child1, child2); 472 } 473 } else if (node1.type_ === DataType.ATTR) { 474 node1.value_ = NodeTools.copyNode(node2.value_, node1); 475 } 476 return true; 477}; 478NodeTools.jinZhi10ToX = function (num, jinzhi) { 479 let ret; 480 switch (jinzhi) { 481 case MAX_BINARY: 482 ret = '0b'; 483 break; 484 case MAX_OCTAL: 485 ret = '0'; 486 break; 487 case MAX_DECIMAL: 488 ret = ''; 489 break; 490 case MAX_HEXADECIMAL: 491 ret = '0x'; 492 break; 493 default: 494 NapiLog.logError(jinzhi + '进制转换失败'); 495 break; 496 } 497 return ret + num.toString(jinzhi); 498}; 499NodeTools.jinZhiXTo10 = function (s) { 500 if (s === null || s.length === 0) { 501 return [0, MAX_DECIMAL]; 502 } 503 504 s = s.trim(); 505 if (!isFinite(s)) { 506 return [undefined, MAX_DECIMAL]; 507 } 508 509 try { 510 if (s[0] === '0') { 511 if (s.length === 1) { 512 return [BigInt(s), MAX_DECIMAL]; 513 } else if (s[1] === 'b' || s[1] === 'B') { 514 return [BigInt(s), MAX_BINARY]; 515 } else if (s[1] === 'x' || s[1] === 'X') { 516 return [BigInt(s), MAX_HEXADECIMAL]; 517 } else { 518 return [BigInt('0o' + s.substring(1)), MAX_OCTAL]; 519 } 520 } else { 521 return [BigInt(s), MAX_DECIMAL]; 522 } 523 } catch (ex) { 524 NapiLog.logError(ex.message); 525 return [undefined, MAX_DECIMAL]; 526 } 527}; 528 529NodeTools.createNewNode = function (type, name, value, nodetype) { 530 let ret = new Object(); 531 ret.type_ = type; 532 ret.name_ = name; 533 ret.value_ = value; 534 ret.isOpen_ = true; 535 if (type < DataType.STRING) { 536 ret.jinzhi_ = MAX_DECIMAL; 537 } 538 if (type === DataType.NODE) { 539 ret.nodeType_ = nodetype; 540 } 541 return ret; 542}; 543NodeTools.arrayToString = function (node, maxw) { 544 let ret = ''; 545 let type = DataType.INT8; 546 for (let d in node.value_) { 547 if (type < node.value_[d].type_) { 548 type = node.value_[d].type_; 549 } 550 } 551 let line = ''; 552 for (let d in node.value_) { 553 if (d > 0) { 554 line += ','; 555 if (maxw !== undefined) { 556 if (line.length >= maxw) { 557 ret += line + '\n'; 558 line = ''; 559 } 560 } 561 } 562 if (type === DataType.STRING) { 563 line += '"' + node.value_[d].value_ + '"'; 564 } else { 565 line += NodeTools.jinZhi10ToX(node.value_[d].value_, node.value_[d].jinzhi_); 566 } 567 } 568 ret += line; 569 return ret; 570}; 571 572NodeTools.stringToArray = function (s) { 573 let type = DataType.INT8; 574 let ret = []; 575 s = s.replace(/\n/g, ''); 576 if (s.length <= 0) { 577 return ret; 578 } 579 if (s.indexOf('"') >= 0) { 580 type = DataType.STRING; 581 let p = 0; 582 let stat = 0; 583 let v; 584 while (p < s.length && stat < STAT_SIZE) { 585 switch (stat) { 586 case 0: 587 if (s[p] === '"') { 588 stat = 1; 589 v = ''; 590 } else if (s[p] !== ' ') { 591 stat = STAT_SIZE; 592 } 593 break; 594 case 1: 595 if (s[p] === '"') { 596 stat = 2; 597 ret.push(NodeTools.createNewNode(type, '', v)); 598 } else { 599 v += s[p]; 600 } 601 break; 602 case 2: 603 if (s[p] === ',') { 604 stat = 0; 605 } 606 else if (s[p] !== ' ') { 607 stat = STAT_SIZE; 608 } 609 break; 610 } 611 p += 1; 612 } 613 } else { 614 let arr = s.split(','); 615 stringToArrayWithQuote(ret, type, arr); 616 } 617 return ret; 618}; 619 620function stringToArrayWithQuote(ret, type, arr) { 621 for (let i in arr) { 622 let num = NodeTools.jinZhiXTo10(arr[i]); 623 if (num[0] === undefined) { 624 num[0] = 0; 625 } 626 let attr = NodeTools.createNewNode(type, '', num[0]); 627 attr.jinzhi_ = num[1]; 628 ret.push(attr); 629 if (num[0] <= 0xff) { 630 if (type < DataType.INT8) { 631 type = DataType.INT8; 632 } 633 } else if (num[0] <= 0xffff) { 634 if (type < DataType.INT16) { 635 type = DataType.INT16; 636 } 637 } else if (num[0] <= 0xffffffff) { 638 if (type < DataType.INT32) { 639 type = DataType.INT32; 640 } 641 } else { 642 type = DataType.INT64; 643 } 644 } 645 if (type !== DataType.INT8) { 646 for (let i in ret) { 647 ret[i].type_ = type; 648 } 649 } 650} 651 652module.exports = { 653 NodeTools, 654 DataType, 655 NodeType, 656}; 657