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