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 { TokenType } = require('./lexer'); 18 19var ObjectType = { 20 PARSEROP_UINT8: 0x01, 21 PARSEROP_UINT16: 2, 22 PARSEROP_UINT32: 3, 23 PARSEROP_UINT64: 4, 24 PARSEROP_STRING: 5, 25 PARSEROP_CONFNODE: 6, 26 PARSEROP_CONFTERM: 7, 27 PARSEROP_ARRAY: 8, 28 PARSEROP_NODEREF: 9, 29 PARSEROP_DELETE: 10, 30 PARSEROP_BOOL: 11, 31}; 32 33var NodeRefType = { 34 NODE_NOREF: 0, 35 NODE_COPY: 1, 36 NODE_REF: 2, 37 NODE_DELETE: 3, 38 NODE_TEMPLATE: 4, 39 NODE_INHERIT: 5, 40}; 41 42var HcsErrorNo = { 43 NOERR: 0, 44 EFAIL: 1, 45 EOOM: 2, 46 EOPTION: 3, 47 EREOPENF: 4, 48 EINVALF: 5, 49 EINVALARG: 6, 50 EDECOMP: 7, 51 EOUTPUT: 8, 52 EASTWALKBREAK: 9, 53}; 54 55var UINT8_MAX = 255; 56var UINT16_MAX = 65535; 57var UINT32_MAX = 0xffffffff; 58var UINT64_MAX = 0xffffffffffffffff; 59 60class AstObject { 61 constructor(name, type, value, bindToken, jinzhi) { 62 let callType = Object.prototype.toString.call(name); 63 if (callType == '[object Object]') { 64 this.constructorSis(name.name_, name.type_, name.stringValue_); 65 this.integerValue_ = name.integerValue_; 66 } else if (callType == '[object String]') { 67 if (Object.prototype.toString.call(value) == '[object Number]') { 68 if (Object.prototype.toString.call(bindToken) == '[object Object]') { 69 this.constructorSiit(name, type, value, bindToken, jinzhi); 70 } else { 71 this.constructorSii(name, type, value, jinzhi); 72 } 73 } else if (Object.prototype.toString.call(value) == '[object String]') { 74 if (Object.prototype.toString.call(bindToken) == '[object Object]') { 75 this.constructorSist(name, type, value, bindToken); 76 } else { 77 this.constructorSis(name, type, value); 78 } 79 } else { 80 NapiLog.logError('err1'); 81 } 82 } else { 83 NapiLog.logError('err2'); 84 } 85 } 86 87 constructorSii(name, type, value, jinzhi) { 88 this.type_ = type; 89 this.name_ = name; 90 this.parent_ = null; 91 this.lineno_ = 0; 92 this.opCode_ = 0; 93 this.size_ = 0; 94 this.subSize_ = 0; 95 this.hash_ = 0; 96 this.integerValue_ = value; 97 this.jinzhi_ = jinzhi; 98 } 99 100 constructorSis(name, type, value) { 101 this.constructorSii(name, type, 0, 10); 102 this.stringValue_ = value; 103 } 104 105 constructorSiit(name, type, value, bindToken, jinzhi) { 106 this.constructorSii(name, type, value, jinzhi); 107 this.lineno_ = bindToken.lineNo; 108 this.src_ = bindToken.src; 109 110 switch (type) { 111 case ObjectType.PARSEROP_UINT8: 112 case ObjectType.PARSEROP_UINT16: 113 case ObjectType.PARSEROP_UINT32: 114 case ObjectType.PARSEROP_UINT64: 115 this.type_ = this.fitIntegerValueType(value); 116 break; 117 default: 118 break; 119 } 120 } 121 122 constructorSist(name, type, value, bindToken) { 123 this.constructorSiit(name, type, 0, bindToken, 10); 124 this.stringValue_ = value; 125 } 126 127 fitIntegerValueType(value) { 128 if (value <= UINT8_MAX) { 129 return ObjectType.PARSEROP_UINT8; 130 } else if (value <= UINT16_MAX) { 131 return ObjectType.PARSEROP_UINT16; 132 } else if (value <= UINT32_MAX) { 133 return ObjectType.PARSEROP_UINT32; 134 } else { 135 return ObjectType.PARSEROP_UINT64; 136 } 137 } 138 addChild(childObj) { 139 if (childObj == null) { 140 return false; 141 } 142 if (this.child_ == null) { 143 this.child_ = childObj; 144 let childNext = childObj; 145 while (childNext != null) { 146 childNext.parent_ = this; 147 childNext = childNext.next_; 148 } 149 } else { 150 return this.child_.addPeer(childObj); 151 } 152 153 return true; 154 } 155 156 addPeer(peerObject) { 157 if (peerObject == null) { 158 return false; 159 } 160 161 if (this == peerObject) { 162 NapiLog.logError('add self as peer'); 163 return false; 164 } 165 166 if (this.next_ == null) { 167 this.next_ = peerObject; 168 } else { 169 let lastNode = this.next_; 170 while (lastNode.next_ != null) { 171 lastNode = lastNode.next_; 172 } 173 lastNode.next_ = peerObject; 174 } 175 176 let peer = peerObject; 177 while (peer) { 178 peer.parent_ = this.parent_; 179 peer = peer.next_; 180 } 181 182 return true; 183 } 184 185 merge(srcObj) { 186 if (srcObj.name_ != this.name_) { 187 NapiLog.logError( 188 this.sourceInfo() + 'merge different node to' + srcObj.sourceInfo() 189 ); 190 return false; 191 } 192 193 if (srcObj.type_ != this.type_) { 194 NapiLog.logError( 195 this.sourceInfo() + 'conflict type with ' + srcObj.sourceInfo() 196 ); 197 return false; 198 } 199 200 this.src_ = srcObj.src_; 201 this.lineno_ = srcObj.lineno_; 202 this.stringValue_ = srcObj.stringValue_; 203 this.integerValue_ = srcObj.integerValue_; 204 205 return true; 206 } 207 copy(src, overwrite) { 208 if (src == null) { 209 return false; 210 } 211 212 if (overwrite) { 213 this.src_ = src.src_; 214 this.lineno_ = src.lineno_; 215 this.integerValue_ = src.integerValue_; 216 this.stringValue_ = src.stringValue_; 217 } 218 219 return true; 220 } 221 222 move(src) { 223 if (!this.copy(src, true)) { 224 return false; 225 } 226 src.separate(); 227 return true; 228 } 229 230 sourceInfo() { 231 return this.src_ + ':' + this.lineno_ + ' '; 232 } 233 234 remove() { 235 this.separate(); 236 this.child_ = null; 237 this.next_ = null; 238 } 239 240 lookup(name, type) { 241 let peer = this.child_; 242 while (peer != null) { 243 if (peer.name_ == name && (type == 0 || peer.type_ == type)) { 244 return peer; 245 } 246 247 peer = peer.next_; 248 } 249 250 return null; 251 } 252 253 isNumber() { 254 return ( 255 this.type_ >= ObjectType.PARSEROP_UINT8 && 256 type_ <= ObjectType.PARSEROP_UINT64 257 ); 258 } 259 260 isNode() { 261 return this.type_ == ObjectType.PARSEROP_CONFNODE; 262 } 263 264 isTerm() { 265 return this.type_ == ObjectType.PARSEROP_CONFTERM; 266 } 267 isArray() { 268 return this.type_ == ObjectType.PARSEROP_ARRAY; 269 } 270 separate() { 271 if (this.parent_ == null) { 272 return; 273 } 274 if (this.parent_.child_ == this) { 275 this.parent_.child_ = this.next_; 276 this.next_ = null; 277 return; 278 } 279 280 let pre = this.parent_.child_; 281 while (pre != null) { 282 if (pre.next_ == this) { 283 let tmp = this.next_; 284 this.next_ = null; 285 pre.next_ = tmp; 286 break; 287 } 288 289 pre = pre.next_; 290 } 291 } 292 setParent(parent) { 293 this.parent_ = parent; 294 } 295 SetSize(size) { 296 this.size_ = size; 297 } 298 SetSubSize(size) { 299 this.subSize_ = size; 300 } 301 GetSubSize() { 302 return this.subSize_; 303 } 304 SetHash(hash) { 305 this.hash_ = hash; 306 } 307 GetSize() { 308 return this.size_; 309 } 310 GetHash() { 311 return this.hash_; 312 } 313 next() { 314 return this.next_; 315 } 316 child() { 317 return this.child_; 318 } 319 name() { 320 return this.name_; 321 } 322 stringValue() { 323 return this.stringValue_; 324 } 325 IntegerValue() { 326 return this.integerValue_; 327 } 328 type() { 329 return this.type_; 330 } 331 OpCode() { 332 return this.opCode_; 333 } 334 SetOpCode(opcode) { 335 this.opCode_ = opcode; 336 } 337 hasDuplicateChild() { 338 return false; 339 } 340 isElders(child) { 341 let p = child; 342 while (p != null) { 343 if (p == this) { 344 return true; 345 } 346 p = p.parent_; 347 } 348 return false; 349 } 350 parent() { 351 return this.parent_; 352 } 353} 354 355class ConfigNode extends AstObject { 356 constructor(name, nodeType, refName) { 357 if (Object.prototype.toString.call(name) == '[object String]') { 358 super(name, ObjectType.PARSEROP_CONFNODE, ''); 359 this.refNodePath_ = refName; 360 this.nodeType_ = nodeType; 361 this.inheritIndex_ = 0; 362 this.inheritCount_ = 0; 363 this.templateSignNum_ = 0; 364 } else if (Object.prototype.toString.call(nodeType) == '[object Number]') { 365 super(name.strval, ObjectType.PARSEROP_CONFNODE, 0, name); 366 this.refNodePath_ = refName; 367 this.nodeType_ = nodeType; 368 this.inheritIndex_ = 0; 369 this.inheritCount_ = 0; 370 this.templateSignNum_ = 0; 371 } else { 372 super(name, ObjectType.PARSEROP_CONFNODE, ''); 373 this.refNodePath_ = refName; 374 this.nodeType_ = nodeType; 375 this.inheritIndex_ = 0; 376 this.inheritCount_ = 0; 377 this.templateSignNum_ = 0; 378 379 let child = name.child_; 380 while (child != null) { 381 super.addChild(AstObjectFactory.build(child)); 382 child = child.next(); 383 } 384 } 385 this.subClasses_ = []; 386 } 387 NodeTypeToStr(type) { 388 let type2StringMap = { 389 0: '', 390 1: 'NodeCopy', 391 2: 'NodeReference', 392 3: 'NodeDelete', 393 4: 'NodeInherit', 394 5: 'NodeTemplate', 395 }; 396 return type2StringMap[type]; 397 } 398 399 castFrom(astObject) { 400 return astObject; 401 } 402 getNodeType() { 403 return this.nodeType_; 404 } 405 getRefPath() { 406 return this.refNodePath_; 407 } 408 merge(srcObj) { 409 if (srcObj == null) { 410 return true; 411 } 412 if (!srcObj.isNode() || srcObj.name() != this.name_) { 413 NapiLog.logError( 414 sourceInfo() + 'merge conflict type with ' + srcObj.sourceInfo() 415 ); 416 return false; 417 } 418 419 let srcNode = srcObj; 420 if (srcNode.getNodeType() == TokenType.DELETE) { 421 srcObj.separate(); 422 this.separate(); 423 return true; 424 } 425 426 this.nodeType_ = srcNode.nodeType_; 427 this.refNodePath_ = srcNode.refNodePath_; 428 429 let childSrc = srcObj.child(); 430 while (childSrc != null) { 431 let childSrcNext = childSrc.next(); 432 let childDst = this.lookup(childSrc.name(), childSrc.type()); 433 if (childDst == null) { 434 childSrc.separate(); 435 this.addChild(childSrc); 436 } else if (!childDst.merge(childSrc)) { 437 return false; 438 } 439 childSrc = childSrcNext; 440 } 441 return true; 442 } 443 setNodeType(nodeType) { 444 this.nodeType_ = nodeType; 445 } 446 setRefPath(ref) { 447 this.refNodePath_ = ref; 448 } 449 hasDuplicateChild() { 450 let symMap = {}; 451 let child = this.child_; 452 while (child != null) { 453 let sym = symMap[child.name()]; 454 if (sym != undefined) { 455 NapiLog.logError( 456 child.sourceInfo() + 457 'redefined, first definition at ' + 458 sym.second.sourceInfo() 459 ); 460 return true; 461 } 462 symMap[child.name()] = child; 463 child = child.next(); 464 } 465 466 return false; 467 } 468 inheritExpand(refObj) { 469 if (refObj == null) { 470 NapiLog.logError(sourceInfo() + 'inherit invalid node: ' + refNodePath_); 471 return false; 472 } 473 474 if (!this.copy(refObj, false)) { 475 return false; 476 } 477 478 let templateNode = this.castFrom(refObj); 479 if (!this.compare(templateNode)) { 480 return false; 481 } 482 this.inheritIndex_ = templateNode.inheritCount_++; 483 templateNode.subClasses_.push(this); 484 return true; 485 } 486 refExpand(refObj) { 487 if (this.nodeType_ == NodeRefType.NODE_DELETE) { 488 this.separate(); 489 return true; 490 } 491 492 if (refObj.isElders(this)) { 493 NapiLog.logError( 494 sourceInfo() + 'circular reference ' + refObj.sourceInfo() 495 ); 496 return false; 497 } 498 499 let ret = true; 500 if (this.nodeType_ == NodeRefType.NODE_REF) { 501 ret = this.nodeRefExpand(refObj); 502 } else if (nodeType_ == NodeRefType.NODE_COPY) { 503 ret = nodeCopyExpand(refObj); 504 } 505 506 return ret; 507 } 508 copy(src, overwrite) { 509 let child = src.child(); 510 while (child != null) { 511 let dst = this.lookup(child.name(), child.type()); 512 if (dst == null) { 513 this.addChild(AstObjectFactory.build(child)); 514 } else if (!dst.copy(child, overwrite)) { 515 return false; 516 } 517 child = child.next(); 518 } 519 520 return true; 521 } 522 move(src) { 523 return super.move(src); 524 } 525 nodeRefExpand(ref) { 526 if (ref == null) { 527 NapiLog.logError( 528 sourceInfo() + "reference node '" + refNodePath_ + "' not exist" 529 ); 530 return false; 531 } 532 return ref.move(this); 533 } 534 nodeCopyExpand(ref) { 535 if (ref == null) { 536 NapiLog.logError( 537 sourceInfo() + "copy node '" + refNodePath_ + "' not exist" 538 ); 539 return false; 540 } 541 this.nodeType_ = NodeRefType.NODE_NOREF; 542 return this.copy(ref, false); 543 } 544 compare(other) { 545 let objChild = this.child_; 546 while (objChild != null) { 547 let baseObj = this.lookup(objChild.name(), objChild.type()); 548 if (baseObj == null) { 549 NapiLog.logError( 550 objChild.sourceInfo() + 'not in template node: ' + other.sourceInfo() 551 ); 552 return false; 553 } 554 if (objChild.isNode()) { 555 return this.castFrom(objChild).compare(this.castFrom(baseObj)); 556 } 557 558 objChild = objChild.next(); 559 } 560 return true; 561 } 562 InheritIndex() { 563 return this.inheritIndex_; 564 } 565 InheritCount() { 566 return this.inheritCount_; 567 } 568 TemplateSignNum() { 569 return this.templateSignNum_; 570 } 571 SetTemplateSignNum(sigNum) { 572 this.templateSignNum_ = sigNum; 573 } 574 SubClasses() { 575 return this.subClasses_; 576 } 577} 578 579class ConfigTerm extends AstObject { 580 constructor(name, value) { 581 if (Object.prototype.toString.call(name) == '[object String]') { 582 super(name, ObjectType.PARSEROP_CONFTERM, 0); 583 this.signNum_ = 0; 584 this.child_ = value; 585 if (value != null) { 586 value.this.setParent(this); 587 } 588 } else if ( 589 Object.prototype.toString.call(value) == '[object Object]' || 590 Object.prototype.toString.call(value) == '[object Null]' 591 ) { 592 super(name.strval, ObjectType.PARSEROP_CONFTERM, 0, name); 593 this.signNum_ = 0; 594 this.child_ = value; 595 if (value != null) { 596 value.this.setParent(this); 597 } 598 } else { 599 super(name.name_, ObjectType.PARSEROP_CONFTERM, 0); 600 this.signNum_ = 0; 601 this.child_ = value; 602 if (value != null) { 603 value.this.setParent(this); 604 } 605 super.addChild(AstObjectFactory.build(name.child_)); 606 } 607 } 608 609 castFrom(astObject) { 610 return astObject; 611 } 612 merge(srcObj) { 613 if (!srcObj.isTerm()) { 614 NapiLog.logError( 615 sourceInfo() + 'merge conflict type with ' + srcObj.sourceInfo() 616 ); 617 return false; 618 } 619 620 let value = srcObj.child(); 621 srcObj.child().separate(); 622 this.child_ = null; 623 this.addChild(value); 624 return true; 625 } 626 627 refExpand(refObj) { 628 if (child_.type() == ObjectType.PARSEROP_DELETE) { 629 this.separate(); 630 return true; 631 } 632 633 if (child_.type() != ObjectType.PARSEROP_NODEREF) { 634 return true; 635 } 636 637 if ( 638 refObj == null || 639 !refObj.isNode() || 640 ConfigNode.castFrom(refObj).getNodeType() == NodeRefType.NODE_REF || 641 ConfigNode.castFrom(refObj).getNodeType() == NodeRefType.NODE_TEMPLATE || 642 ConfigNode.castFrom(refObj).getNodeType() == NodeRefType.NODE_DELETE 643 ) { 644 NapiLog.logError( 645 sourceInfo() + "reference invalid node '" + child_.stringValue() + "'" 646 ); 647 return false; 648 } 649 650 this.refNode_ = refObj; 651 return true; 652 } 653 copy(src, overwrite) { 654 if (!overwrite) { 655 return true; 656 } 657 if ( 658 this.child_.type() != src.child().type() && 659 (!this.child_.isNumber() || !src.child().isNumber()) 660 ) { 661 NapiLog.logError( 662 src.sourceInfo() + 663 'overwrite different type with:' + 664 child_.sourceInfo() 665 ); 666 return false; 667 } 668 return this.child_.copy(src.child(), overwrite); 669 } 670 move(src) { 671 return this.child_.move(src.child()); 672 } 673 RefNode() { 674 return this.refNode_; 675 } 676 SetSigNum(sigNum) { 677 this.signNum_ = sigNum; 678 } 679 SigNum() { 680 return this.signNum_; 681 } 682} 683class ConfigArray extends AstObject { 684 constructor(array) { 685 if (Object.prototype.toString.call(array) == '[object Object]') { 686 super('', ObjectType.PARSEROP_ARRAY, 0, array); // bindToken 687 this.arrayType_ = 0; 688 this.arraySize_ = 0; 689 if (array.type == undefined) { 690 let child = array.child_; 691 while (child != null) { 692 super.addChild(AstObjectFactory.build(child)); 693 child = child.next(); 694 } 695 this.arraySize_ = array.arraySize_; 696 this.arrayType_ = array.arrayType_; 697 } 698 } else { 699 super('', ObjectType.PARSEROP_ARRAY, 0); 700 this.arrayType_ = 0; 701 this.arraySize_ = 0; 702 } 703 } 704 705 addChild(childObj) { 706 if (super.addChild(childObj)) { 707 this.arraySize_++; 708 this.arrayType_ = 709 this.arrayType_ > childObj.type() ? this.arrayType_ : childObj.type(); 710 return true; 711 } else { 712 return false; 713 } 714 } 715 716 merge(srcObj) { 717 if (!srcObj.isArray()) { 718 NapiLog.logError( 719 sourceInfo() + 'merge conflict type with ' + srcObj.sourceInfo() 720 ); 721 return false; 722 } 723 724 let value = srcObj.child(); 725 value.separate(); 726 this.child_ = value; 727 return true; 728 } 729 730 copy(src, overwrite) { 731 if (!overwrite) { 732 return true; 733 } 734 let array = ConfigArray.castFrom(src); 735 this.child_ = null; 736 let t = array.child_; 737 while (t != null) { 738 addChild(AstObjectFactory.build(t)); 739 } 740 return true; 741 } 742 743 castFrom(astObject) { 744 return astObject; 745 } 746 747 arraySize() { 748 return this.arraySize_; 749 } 750 751 arrayType() { 752 return this.arrayType_; 753 } 754} 755 756class AstObjectFactory {} 757AstObjectFactory.build = function (object) { 758 switch (object.type()) { 759 case ObjectType.PARSEROP_CONFNODE: 760 return new ConfigNode(object); 761 case ObjectType.PARSEROP_CONFTERM: 762 return new ConfigTerm(object); 763 case ObjectType.PARSEROP_ARRAY: 764 return new ConfigArray(object); 765 default: 766 return new AstObject(object); 767 } 768}; 769 770class Ast { 771 constructor(astRoot) { 772 this.astRoot_ = astRoot; 773 this.redefineChecked_ = false; 774 } 775 setw(l) { 776 let ret = ''; 777 for (let i = 0; i < l; i++) ret += ' '; 778 return ret; 779 } 780 781 dump(prefix) { 782 NapiLog.logError('dump ', prefix, ' AST:'); 783 this.walkForward(this.astRoot_, (current, walkDepth) => { 784 switch (current.type_) { 785 case ObjectType.PARSEROP_UINT8: 786 case ObjectType.PARSEROP_UINT16: 787 case ObjectType.PARSEROP_UINT32: 788 case ObjectType.PARSEROP_UINT64: 789 NapiLog.logInfo( 790 this.setw(walkDepth * 4) + '[' + current.integerValue_ + ']' 791 ); 792 break; 793 case ObjectType.PARSEROP_STRING: // 5 794 NapiLog.logInfo(this.setw(walkDepth * 4) + current.stringValue_); 795 break; 796 case ObjectType.PARSEROP_CONFNODE: // 6 content 797 if (current.name_ == 'blockSize') { 798 current.name_ = 'blockSize'; 799 } 800 NapiLog.logInfo(this.setw(walkDepth * 4) + current.name_ + ' :'); 801 break; 802 case ObjectType.PARSEROP_CONFTERM: // 7 Attribute name 803 if (current.name_ == 'funcNum') { 804 current.name_ = 'funcNum'; 805 } 806 NapiLog.logInfo(this.setw(walkDepth * 4) + current.name_ + ' = '); 807 break; 808 case ObjectType.PARSEROP_ARRAY: 809 NapiLog.logInfo(this.setw(walkDepth * 4) + current.name_); 810 break; 811 case ObjectType.PARSEROP_NODEREF: 812 NapiLog.logInfo(this.setw(walkDepth * 4) + current.name_); 813 break; 814 case ObjectType.PARSEROP_DELETE: 815 NapiLog.logInfo(this.setw(walkDepth * 4) + current.name_); 816 break; 817 } 818 return HcsErrorNo.NOERR; 819 }); 820 } 821 822 getAstRoot() { 823 return this.astRoot_; 824 } 825 826 merge(astList) { 827 if (!this.redefineCheck()) { 828 return false; 829 } 830 for (let i = 0; i < astList.length; i++) { 831 let astIt = astList[i]; 832 if (!astIt.redefineCheck()) { 833 return false; 834 } 835 if (this.astRoot_ != null && !this.astRoot_.merge(astIt.astRoot_)) { 836 return false; 837 } else if (this.astRoot_ == null) { 838 this.astRoot_ = astIt.getAstRoot(); 839 } 840 } 841 return true; 842 } 843 844 getchild(node, name) { 845 let p = node.child_; 846 while (p != null) { 847 if (p.name_ == name) { 848 return p; 849 } 850 p = p.next_; 851 } 852 return null; 853 } 854 855 getpath(node) { 856 NapiLog.logError('----path start----'); 857 let p = node; 858 while (p != null) { 859 NapiLog.logError(p.name_); 860 p = p.parent_; 861 } 862 NapiLog.logError('----path end----'); 863 } 864 865 expand() { 866 let n1, n2; 867 868 if (!this.redefineCheck()) { 869 return false; 870 } 871 872 if (this.astRoot_.lookup('module', ObjectType.PARSEROP_CONFTERM) == null) { 873 NapiLog.logError( 874 astRoot_.sourceInfo() + "miss 'module' attribute under root node" 875 ); 876 return false; 877 } 878 879 if (!this.nodeExpand()) { 880 return false; 881 } 882 883 if (!this.inheritExpand()) { 884 return false; 885 } 886 this.dump('expanded'); 887 return true; 888 } 889 890 nodeExpand() { 891 return this.walkBackward(this.astRoot_, (current, walkDepth) => { 892 if (current.isNode()) { 893 let node = current; 894 if (node.getNodeType() == NodeRefType.NODE_DELETE) { 895 current.remove(); 896 child_; 897 return HcsErrorNo.NOERR; 898 } 899 if ( 900 node.getNodeType() != NodeRefType.NODE_REF && 901 node.getNodeType() != NodeRefType.NODE_COPY 902 ) { 903 return HcsErrorNo.NOERR; 904 } 905 906 let ret = node.refExpand(this.lookup(current, node.getRefPath())); 907 if (!ret) { 908 return HcsErrorNo.EFAIL; 909 } 910 } else if (current.isTerm()) { 911 let ref; 912 if (current.child_.type() == ObjectType.PARSEROP_DELETE) { 913 current.remove(); 914 return HcsErrorNo.NOERR; 915 } 916 if (current.child_.type() == ObjectType.PARSEROP_NODEREF) { 917 ref = lookup(current, current.child_.stringValue()); 918 if (!current.refExpand(ref)) { 919 return HcsErrorNo.EFAIL; 920 } 921 } 922 } 923 return HcsErrorNo.NOERR; 924 }); 925 } 926 927 walkBackward(startObject, callback) { 928 let backWalkObj = startObject; 929 let next = null; 930 let parent = null; 931 let walkDepth = 0; 932 let preVisited = false; 933 934 while (backWalkObj != null) { 935 let backWalk = true; 936 if (backWalkObj.child_ == null || preVisited) { 937 next = backWalkObj.next_; 938 parent = backWalkObj.parent(); 939 940 if (callback(backWalkObj, walkDepth) != HcsErrorNo.NOERR) { 941 return false; 942 } 943 } else if (backWalkObj.child_) { 944 walkDepth++; 945 backWalkObj = backWalkObj.child_; 946 backWalk = false; 947 } 948 if (backWalk) { 949 if (backWalkObj == startObject) { 950 break; 951 } 952 953 if (next != null) { 954 backWalkObj = next; 955 preVisited = false; 956 } else { 957 backWalkObj = parent; 958 preVisited = true; 959 walkDepth--; 960 } 961 } 962 } 963 return true; 964 } 965 966 inheritExpand() { 967 return this.walkForward(this.astRoot_, (current, ii) => { 968 if (current.isNode()) { 969 let node = current; 970 if (node.getNodeType() != NodeRefType.NODE_INHERIT) { 971 return HcsErrorNo.NOERR; 972 } 973 let inherit = this.lookup(current, node.getRefPath()); 974 if (!node.inheritExpand(inherit)) { 975 return HcsErrorNo.EFAIL; 976 } 977 } 978 979 return HcsErrorNo.NOERR; 980 }); 981 } 982 983 redefineCheck() { 984 if (this.redefineChecked_) { 985 return true; 986 } 987 988 let ret = this.walkForward(this.astRoot_, (current, ii) => { 989 if (current.isNode() && current.hasDuplicateChild()) { 990 return HcsErrorNo.EFAIL; 991 } 992 993 return HcsErrorNo.NOERR; 994 }); 995 996 this.redefineChecked_ = true; 997 return ret; 998 } 999 1000 walkForward(startObject, callback) { 1001 let forwardWalkObj = startObject; 1002 let walkDepth = 0; 1003 let preVisited = false; 1004 1005 while (forwardWalkObj != null) { 1006 let forward = true; 1007 if (!preVisited) { 1008 let ret = callback(forwardWalkObj, walkDepth); 1009 if (ret && ret != HcsErrorNo.EASTWALKBREAK) { 1010 return false; 1011 } else if ( 1012 ret != HcsErrorNo.EASTWALKBREAK && 1013 forwardWalkObj.child_ != null 1014 ) { 1015 walkDepth++; 1016 forwardWalkObj = forwardWalkObj.child_; 1017 forward = false; 1018 } 1019 } 1020 1021 if (forward) { 1022 if (forwardWalkObj == startObject) { 1023 break; 1024 } 1025 1026 if (forwardWalkObj.next_ != null) { 1027 forwardWalkObj = forwardWalkObj.next_; 1028 preVisited = false; 1029 } else { 1030 forwardWalkObj = forwardWalkObj.parent(); 1031 preVisited = true; 1032 walkDepth--; 1033 } 1034 } 1035 } 1036 1037 return true; 1038 } 1039 1040 lookup(startObj, path) { 1041 if (path.indexOf('.') < 0) { 1042 return startObj.parent_.lookup(path, 0); 1043 } 1044 1045 let splitPath = this.splitNodePath(path, '.'); 1046 } 1047 splitNodePath(path, separator) { 1048 let splitList = path.split(separator); 1049 return splitList; 1050 } 1051} 1052 1053module.exports = { 1054 AstObject, 1055 ConfigNode, 1056 ConfigTerm, 1057 ConfigArray, 1058 NodeRefType, 1059 ObjectType, 1060 Ast, 1061}; 1062